@mcp-z/client 1.2.0 → 1.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 (95) hide show
  1. package/README.md +22 -0
  2. package/dist/cjs/auth/capability-discovery.js +16 -6
  3. package/dist/cjs/auth/capability-discovery.js.map +1 -1
  4. package/dist/cjs/auth/discovery-fetch.d.cts +22 -2
  5. package/dist/cjs/auth/discovery-fetch.d.ts +22 -2
  6. package/dist/cjs/auth/discovery-fetch.js +440 -124
  7. package/dist/cjs/auth/discovery-fetch.js.map +1 -1
  8. package/dist/cjs/auth/interactive-oauth-flow.d.cts +9 -2
  9. package/dist/cjs/auth/interactive-oauth-flow.d.ts +9 -2
  10. package/dist/cjs/auth/interactive-oauth-flow.js +29 -11
  11. package/dist/cjs/auth/interactive-oauth-flow.js.map +1 -1
  12. package/dist/cjs/auth/oauth-callback-listener.js +4 -0
  13. package/dist/cjs/auth/oauth-callback-listener.js.map +1 -1
  14. package/dist/cjs/auth/types.d.cts +29 -4
  15. package/dist/cjs/auth/types.d.ts +29 -4
  16. package/dist/cjs/auth/types.js.map +1 -1
  17. package/dist/cjs/client-helpers.d.cts +5 -6
  18. package/dist/cjs/client-helpers.d.ts +5 -6
  19. package/dist/cjs/client-helpers.js +8 -8
  20. package/dist/cjs/client-helpers.js.map +1 -1
  21. package/dist/cjs/connection/connect-client.d.cts +12 -11
  22. package/dist/cjs/connection/connect-client.d.ts +12 -11
  23. package/dist/cjs/connection/connect-client.js +31 -47
  24. package/dist/cjs/connection/connect-client.js.map +1 -1
  25. package/dist/cjs/connection/existing-process-transport.d.cts +1 -2
  26. package/dist/cjs/connection/existing-process-transport.d.ts +1 -2
  27. package/dist/cjs/connection/existing-process-transport.js +3 -3
  28. package/dist/cjs/connection/existing-process-transport.js.map +1 -1
  29. package/dist/cjs/dcr/dcr-authenticator.d.cts +36 -5
  30. package/dist/cjs/dcr/dcr-authenticator.d.ts +36 -5
  31. package/dist/cjs/dcr/dcr-authenticator.js +473 -57
  32. package/dist/cjs/dcr/dcr-authenticator.js.map +1 -1
  33. package/dist/cjs/dcr/dynamic-client-registrar.d.cts +2 -2
  34. package/dist/cjs/dcr/dynamic-client-registrar.d.ts +2 -2
  35. package/dist/cjs/dcr/dynamic-client-registrar.js +10 -11
  36. package/dist/cjs/dcr/dynamic-client-registrar.js.map +1 -1
  37. package/dist/cjs/index.d.cts +2 -0
  38. package/dist/cjs/index.d.ts +2 -0
  39. package/dist/cjs/index.js +8 -2
  40. package/dist/cjs/index.js.map +1 -1
  41. package/dist/cjs/lib/url-utils.d.cts +17 -0
  42. package/dist/cjs/lib/url-utils.d.ts +17 -0
  43. package/dist/cjs/lib/url-utils.js +22 -2
  44. package/dist/cjs/lib/url-utils.js.map +1 -1
  45. package/dist/cjs/response-wrappers.d.cts +1 -1
  46. package/dist/cjs/response-wrappers.d.ts +1 -1
  47. package/dist/cjs/response-wrappers.js.map +1 -1
  48. package/dist/cjs/search/search.d.cts +1 -1
  49. package/dist/cjs/search/search.d.ts +1 -1
  50. package/dist/cjs/search/search.js.map +1 -1
  51. package/dist/esm/auth/capability-discovery.js +16 -6
  52. package/dist/esm/auth/capability-discovery.js.map +1 -1
  53. package/dist/esm/auth/discovery-fetch.d.ts +22 -2
  54. package/dist/esm/auth/discovery-fetch.js +234 -54
  55. package/dist/esm/auth/discovery-fetch.js.map +1 -1
  56. package/dist/esm/auth/interactive-oauth-flow.d.ts +9 -2
  57. package/dist/esm/auth/interactive-oauth-flow.js +28 -10
  58. package/dist/esm/auth/interactive-oauth-flow.js.map +1 -1
  59. package/dist/esm/auth/oauth-callback-listener.js +4 -0
  60. package/dist/esm/auth/oauth-callback-listener.js.map +1 -1
  61. package/dist/esm/auth/types.d.ts +29 -4
  62. package/dist/esm/auth/types.js.map +1 -1
  63. package/dist/esm/client-helpers.d.ts +5 -6
  64. package/dist/esm/client-helpers.js +8 -8
  65. package/dist/esm/client-helpers.js.map +1 -1
  66. package/dist/esm/connection/connect-client.d.ts +12 -11
  67. package/dist/esm/connection/connect-client.js +32 -38
  68. package/dist/esm/connection/connect-client.js.map +1 -1
  69. package/dist/esm/connection/existing-process-transport.d.ts +1 -2
  70. package/dist/esm/connection/existing-process-transport.js +1 -1
  71. package/dist/esm/connection/existing-process-transport.js.map +1 -1
  72. package/dist/esm/dcr/dcr-authenticator.d.ts +36 -5
  73. package/dist/esm/dcr/dcr-authenticator.js +129 -52
  74. package/dist/esm/dcr/dcr-authenticator.js.map +1 -1
  75. package/dist/esm/dcr/dynamic-client-registrar.d.ts +2 -2
  76. package/dist/esm/dcr/dynamic-client-registrar.js +7 -6
  77. package/dist/esm/dcr/dynamic-client-registrar.js.map +1 -1
  78. package/dist/esm/index.d.ts +2 -0
  79. package/dist/esm/index.js +4 -1
  80. package/dist/esm/index.js.map +1 -1
  81. package/dist/esm/lib/url-utils.d.ts +17 -0
  82. package/dist/esm/lib/url-utils.js +34 -2
  83. package/dist/esm/lib/url-utils.js.map +1 -1
  84. package/dist/esm/response-wrappers.d.ts +1 -1
  85. package/dist/esm/response-wrappers.js.map +1 -1
  86. package/dist/esm/search/search.d.ts +1 -1
  87. package/dist/esm/search/search.js.map +1 -1
  88. package/package.json +4 -4
  89. package/dist/cjs/monkey-patches.d.cts +0 -6
  90. package/dist/cjs/monkey-patches.d.ts +0 -6
  91. package/dist/cjs/monkey-patches.js +0 -233
  92. package/dist/cjs/monkey-patches.js.map +0 -1
  93. package/dist/esm/monkey-patches.d.ts +0 -6
  94. package/dist/esm/monkey-patches.js +0 -32
  95. package/dist/esm/monkey-patches.js.map +0 -1
@@ -31,7 +31,7 @@ import { generatePkce } from './pkce.js';
31
31
  * 'https://example.com/oauth/token',
32
32
  * 'client-id',
33
33
  * 'client-secret',
34
- * { port, scopes: ['read', 'write'] }
34
+ * { port, issuer: 'https://example.com', resource: 'https://example.com/mcp', scopes: ['read', 'write'] }
35
35
  * );
36
36
  */ async performAuthFlow(authorizationEndpoint, tokenEndpoint, clientId, clientSecret, options) {
37
37
  var _options_logger;
@@ -60,10 +60,8 @@ import { generatePkce } from './pkce.js';
60
60
  if (options.scopes && options.scopes.length > 0) {
61
61
  authUrl.searchParams.set('scope', options.scopes.join(' '));
62
62
  }
63
- // Add resource parameter if specified (RFC 8707)
64
- if (options.resource) {
65
- authUrl.searchParams.set('resource', options.resource);
66
- }
63
+ // Audience-bind the request to the resource server (RFC 8707)
64
+ authUrl.searchParams.set('resource', options.resource);
67
65
  // Add PKCE parameters if generated (RFC 7636)
68
66
  if (pkce) {
69
67
  authUrl.searchParams.set('code_challenge', pkce.codeChallenge);
@@ -82,8 +80,9 @@ import { generatePkce } from './pkce.js';
82
80
  // Wait for callback with timeout
83
81
  const timeout = options.timeout || (options.headless ? 60000 : 300000);
84
82
  const result = await callbackListener.waitForCallback(timeout);
83
+ this.assertResponseIssuer(result.iss, options, logger);
85
84
  // Exchange authorization code for tokens (with PKCE verifier if used)
86
- const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, (_options_allowLoopback = options.allowLoopback) !== null && _options_allowLoopback !== void 0 ? _options_allowLoopback : false, pkce === null || pkce === void 0 ? void 0 : pkce.codeVerifier);
85
+ const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, options.resource, (_options_allowLoopback = options.allowLoopback) !== null && _options_allowLoopback !== void 0 ? _options_allowLoopback : false, pkce === null || pkce === void 0 ? void 0 : pkce.codeVerifier);
87
86
  return tokens;
88
87
  } catch (error) {
89
88
  logger.error('❌ OAuth flow failed:', error instanceof Error ? error.message : String(error));
@@ -94,16 +93,33 @@ import { generatePkce } from './pkce.js';
94
93
  }
95
94
  }
96
95
  /**
96
+ * Rejects an authorization response that was not minted by the issuer
97
+ * discovered before the flow started (RFC 9207 authorization-server mix-up).
98
+ */ assertResponseIssuer(iss, options, logger) {
99
+ if (iss !== undefined) {
100
+ if (iss !== options.issuer) {
101
+ throw new Error(`Authorization response issuer mismatch: got '${iss}', expected '${options.issuer}' - refusing to redeem the authorization code`);
102
+ }
103
+ return;
104
+ }
105
+ if (options.authorizationResponseIssSupported) {
106
+ throw new Error(`Authorization server '${options.issuer}' advertises authorization_response_iss_parameter_supported but omitted 'iss' - refusing to redeem the authorization code`);
107
+ }
108
+ logger.debug(`⚠️ Authorization response carried no 'iss' and '${options.issuer}' does not advertise support for it (RFC 9207)`);
109
+ }
110
+ /**
97
111
  * Exchanges an authorization code for access and refresh tokens.
112
+ * @param resource - Canonical resource server URI, audience-binding the token (RFC 8707).
98
113
  * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.
99
114
  * @param codeVerifier - Optional PKCE code verifier (RFC 7636).
100
- */ async exchangeCodeForTokens(tokenEndpoint, code, clientId, clientSecret, redirectUri, allowLoopback, codeVerifier) {
115
+ */ async exchangeCodeForTokens(tokenEndpoint, code, clientId, clientSecret, redirectUri, resource, allowLoopback, codeVerifier) {
101
116
  const params = new URLSearchParams({
102
117
  grant_type: 'authorization_code',
103
118
  code,
104
119
  redirect_uri: redirectUri,
105
120
  client_id: clientId,
106
- client_secret: clientSecret
121
+ client_secret: clientSecret,
122
+ resource
107
123
  });
108
124
  // Add PKCE code verifier if provided (RFC 7636)
109
125
  if (codeVerifier) {
@@ -148,10 +164,11 @@ import { generatePkce } from './pkce.js';
148
164
  * @param refreshToken - Refresh token from a previous token set.
149
165
  * @param clientId - OAuth client ID.
150
166
  * @param clientSecret - OAuth client secret.
167
+ * @param resource - Canonical resource server URI, audience-binding the token (RFC 8707).
151
168
  * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.
152
169
  * @returns New token set with a refreshed access token.
153
170
  * @throws Error if refresh fails.
154
- */ async refreshTokens(tokenEndpoint, refreshToken, clientId, clientSecret, allowLoopback = false) {
171
+ */ async refreshTokens(tokenEndpoint, refreshToken, clientId, clientSecret, resource, allowLoopback = false) {
155
172
  // See exchangeCodeForTokens - tokenEndpoint is remote-controlled discovery data.
156
173
  const response = await discoveryFetch(tokenEndpoint, {
157
174
  method: 'POST',
@@ -164,7 +181,8 @@ import { generatePkce } from './pkce.js';
164
181
  grant_type: 'refresh_token',
165
182
  refresh_token: refreshToken,
166
183
  client_id: clientId,
167
- client_secret: clientSecret
184
+ client_secret: clientSecret,
185
+ resource
168
186
  })
169
187
  }, 'token endpoint', {
170
188
  allowLoopback
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/interactive-oauth-flow.ts"],"sourcesContent":["/**\n * OAuth Authorization Flow Handler\n * Manages browser-based OAuth flows and token exchange with PKCE support\n */\n\nimport * as child_process from 'node:child_process';\nimport { logger as defaultLogger } from '../utils/logger.ts';\nimport { discoveryFetch } from './discovery-fetch.ts';\nimport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nimport { generatePkce } from './pkce.ts';\nimport type { OAuthFlowOptions, PkceParams, TokenSet } from './types.ts';\n\n/**\n * OAuth token response from token endpoint\n */\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope?: string;\n token_type?: string;\n}\n\n/**\n * InteractiveOAuthFlow manages the complete OAuth authorization code flow\n */\nexport class InteractiveOAuthFlow {\n /**\n * Perform OAuth authorization code flow\n *\n * @param authorizationEndpoint - OAuth authorization endpoint URL\n * @param tokenEndpoint - OAuth token endpoint URL\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param options - Flow options (port is required - use get-port to find available port)\n * @returns Token set with access and refresh tokens\n *\n * @throws Error if flow fails or times out\n *\n * @example\n * import getPort from 'get-port';\n *\n * const flow = new InteractiveOAuthFlow();\n * const port = await getPort();\n * const tokens = await flow.performAuthFlow(\n * 'https://example.com/oauth/authorize',\n * 'https://example.com/oauth/token',\n * 'client-id',\n * 'client-secret',\n * { port, scopes: ['read', 'write'] }\n * );\n */\n async performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet> {\n const logger = options.logger ?? defaultLogger;\n const callbackListener = new OAuthCallbackListener({ port: options.port, logger });\n\n // Generate PKCE parameters if requested (RFC 7636)\n let pkce: PkceParams | undefined;\n if (options.pkce) {\n logger.debug('🔐 Generating PKCE parameters...');\n pkce = await generatePkce();\n }\n\n try {\n // Start callback server\n await callbackListener.start();\n\n // Build redirect URI\n const redirectUri = options.redirectUri || `http://localhost:${options.port}/callback`;\n\n // Build authorization URL\n const authUrl = new URL(authorizationEndpoint);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n\n if (options.scopes && options.scopes.length > 0) {\n authUrl.searchParams.set('scope', options.scopes.join(' '));\n }\n\n // Add resource parameter if specified (RFC 8707)\n if (options.resource) {\n authUrl.searchParams.set('resource', options.resource);\n }\n\n // Add PKCE parameters if generated (RFC 7636)\n if (pkce) {\n authUrl.searchParams.set('code_challenge', pkce.codeChallenge);\n authUrl.searchParams.set('code_challenge_method', pkce.codeChallengeMethod);\n }\n\n // Open browser or print URL for headless mode\n if (options.headless) {\n logger.info('🔗 Please visit this URL to authorize:');\n logger.info(authUrl.toString());\n logger.info('Waiting for callback...');\n } else {\n logger.debug('🌐 Opening browser for OAuth authorization...');\n // Try to open browser (requires 'open' package or native command)\n await this.openBrowser(authUrl.toString());\n }\n\n // Wait for callback with timeout\n const timeout = options.timeout || (options.headless ? 60000 : 300000);\n const result = await callbackListener.waitForCallback(timeout);\n\n // Exchange authorization code for tokens (with PKCE verifier if used)\n const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, options.allowLoopback ?? false, pkce?.codeVerifier);\n\n return tokens;\n } catch (error) {\n logger.error('❌ OAuth flow failed:', error instanceof Error ? error.message : String(error));\n throw error;\n } finally {\n // Always close callback server\n await callbackListener.stop();\n }\n }\n\n /**\n * Exchanges an authorization code for access and refresh tokens.\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.\n * @param codeVerifier - Optional PKCE code verifier (RFC 7636).\n */\n private async exchangeCodeForTokens(tokenEndpoint: string, code: string, clientId: string, clientSecret: string, redirectUri: string, allowLoopback: boolean, codeVerifier?: string): Promise<TokenSet> {\n const params = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n // Add PKCE code verifier if provided (RFC 7636)\n if (codeVerifier) {\n params.set('code_verifier', codeVerifier);\n }\n\n // tokenEndpoint is remote-controlled discovery data; discoveryFetch blocks\n // a private/internal target before the client secret is sent to it.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: params,\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Refreshes an access token using a refresh token.\n * @param tokenEndpoint - OAuth token endpoint URL.\n * @param refreshToken - Refresh token from a previous token set.\n * @param clientId - OAuth client ID.\n * @param clientSecret - OAuth client secret.\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.\n * @returns New token set with a refreshed access token.\n * @throws Error if refresh fails.\n */\n async refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string, allowLoopback = false): Promise<TokenSet> {\n // See exchangeCodeForTokens - tokenEndpoint is remote-controlled discovery data.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token refresh response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || refreshToken, // Reuse old refresh token if not provided\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Open browser to authorization URL\n * Uses platform-specific command to open default browser\n */\n private async openBrowser(url: string): Promise<void> {\n // Determine platform-specific command\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (platform === 'win32') {\n command = 'cmd';\n args = ['/c', 'start', url];\n } else {\n // Linux and others\n command = 'xdg-open';\n args = [url];\n }\n\n // Spawn browser process\n const child = child_process.spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n }\n}\n"],"names":["child_process","logger","defaultLogger","discoveryFetch","OAuthCallbackListener","generatePkce","InteractiveOAuthFlow","performAuthFlow","authorizationEndpoint","tokenEndpoint","clientId","clientSecret","options","callbackListener","port","pkce","debug","start","redirectUri","authUrl","URL","searchParams","set","scopes","length","join","resource","codeChallenge","codeChallengeMethod","headless","info","toString","openBrowser","timeout","result","waitForCallback","tokens","exchangeCodeForTokens","code","allowLoopback","codeVerifier","error","Error","message","String","stop","params","URLSearchParams","grant_type","redirect_uri","client_id","client_secret","response","method","headers","Accept","Connection","body","ok","errorText","text","status","data","json","access_token","tokenSet","accessToken","refreshToken","refresh_token","expiresAt","Date","now","expires_in","scope","split","refreshTokens","url","platform","process","command","args","child","spawn","detached","stdio","unref"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/interactive-oauth-flow.ts"],"sourcesContent":["/**\n * OAuth Authorization Flow Handler\n * Manages browser-based OAuth flows and token exchange with PKCE support\n */\n\nimport * as child_process from 'node:child_process';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { discoveryFetch } from './discovery-fetch.ts';\nimport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nimport { generatePkce } from './pkce.ts';\nimport type { OAuthFlowOptions, PkceParams, TokenSet } from './types.ts';\n\n/**\n * OAuth token response from token endpoint\n */\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope?: string;\n token_type?: string;\n}\n\n/**\n * InteractiveOAuthFlow manages the complete OAuth authorization code flow\n */\nexport class InteractiveOAuthFlow {\n /**\n * Perform OAuth authorization code flow\n *\n * @param authorizationEndpoint - OAuth authorization endpoint URL\n * @param tokenEndpoint - OAuth token endpoint URL\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param options - Flow options (port is required - use get-port to find available port)\n * @returns Token set with access and refresh tokens\n *\n * @throws Error if flow fails or times out\n *\n * @example\n * import getPort from 'get-port';\n *\n * const flow = new InteractiveOAuthFlow();\n * const port = await getPort();\n * const tokens = await flow.performAuthFlow(\n * 'https://example.com/oauth/authorize',\n * 'https://example.com/oauth/token',\n * 'client-id',\n * 'client-secret',\n * { port, issuer: 'https://example.com', resource: 'https://example.com/mcp', scopes: ['read', 'write'] }\n * );\n */\n async performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet> {\n const logger = options.logger ?? defaultLogger;\n const callbackListener = new OAuthCallbackListener({ port: options.port, logger });\n\n // Generate PKCE parameters if requested (RFC 7636)\n let pkce: PkceParams | undefined;\n if (options.pkce) {\n logger.debug('🔐 Generating PKCE parameters...');\n pkce = await generatePkce();\n }\n\n try {\n // Start callback server\n await callbackListener.start();\n\n // Build redirect URI\n const redirectUri = options.redirectUri || `http://localhost:${options.port}/callback`;\n\n // Build authorization URL\n const authUrl = new URL(authorizationEndpoint);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n\n if (options.scopes && options.scopes.length > 0) {\n authUrl.searchParams.set('scope', options.scopes.join(' '));\n }\n\n // Audience-bind the request to the resource server (RFC 8707)\n authUrl.searchParams.set('resource', options.resource);\n\n // Add PKCE parameters if generated (RFC 7636)\n if (pkce) {\n authUrl.searchParams.set('code_challenge', pkce.codeChallenge);\n authUrl.searchParams.set('code_challenge_method', pkce.codeChallengeMethod);\n }\n\n // Open browser or print URL for headless mode\n if (options.headless) {\n logger.info('🔗 Please visit this URL to authorize:');\n logger.info(authUrl.toString());\n logger.info('Waiting for callback...');\n } else {\n logger.debug('🌐 Opening browser for OAuth authorization...');\n // Try to open browser (requires 'open' package or native command)\n await this.openBrowser(authUrl.toString());\n }\n\n // Wait for callback with timeout\n const timeout = options.timeout || (options.headless ? 60000 : 300000);\n const result = await callbackListener.waitForCallback(timeout);\n\n this.assertResponseIssuer(result.iss, options, logger);\n\n // Exchange authorization code for tokens (with PKCE verifier if used)\n const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, options.resource, options.allowLoopback ?? false, pkce?.codeVerifier);\n\n return tokens;\n } catch (error) {\n logger.error('❌ OAuth flow failed:', error instanceof Error ? error.message : String(error));\n throw error;\n } finally {\n // Always close callback server\n await callbackListener.stop();\n }\n }\n\n /**\n * Rejects an authorization response that was not minted by the issuer\n * discovered before the flow started (RFC 9207 authorization-server mix-up).\n */\n private assertResponseIssuer(iss: string | undefined, options: OAuthFlowOptions, logger: Logger): void {\n if (iss !== undefined) {\n if (iss !== options.issuer) {\n throw new Error(`Authorization response issuer mismatch: got '${iss}', expected '${options.issuer}' - refusing to redeem the authorization code`);\n }\n return;\n }\n\n if (options.authorizationResponseIssSupported) {\n throw new Error(`Authorization server '${options.issuer}' advertises authorization_response_iss_parameter_supported but omitted 'iss' - refusing to redeem the authorization code`);\n }\n\n logger.debug(`⚠️ Authorization response carried no 'iss' and '${options.issuer}' does not advertise support for it (RFC 9207)`);\n }\n\n /**\n * Exchanges an authorization code for access and refresh tokens.\n * @param resource - Canonical resource server URI, audience-binding the token (RFC 8707).\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.\n * @param codeVerifier - Optional PKCE code verifier (RFC 7636).\n */\n private async exchangeCodeForTokens(tokenEndpoint: string, code: string, clientId: string, clientSecret: string, redirectUri: string, resource: string, allowLoopback: boolean, codeVerifier?: string): Promise<TokenSet> {\n const params = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n client_id: clientId,\n client_secret: clientSecret,\n resource,\n });\n\n // Add PKCE code verifier if provided (RFC 7636)\n if (codeVerifier) {\n params.set('code_verifier', codeVerifier);\n }\n\n // tokenEndpoint is remote-controlled discovery data; discoveryFetch blocks\n // a private/internal target before the client secret is sent to it.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: params,\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Refreshes an access token using a refresh token.\n * @param tokenEndpoint - OAuth token endpoint URL.\n * @param refreshToken - Refresh token from a previous token set.\n * @param clientId - OAuth client ID.\n * @param clientSecret - OAuth client secret.\n * @param resource - Canonical resource server URI, audience-binding the token (RFC 8707).\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.\n * @returns New token set with a refreshed access token.\n * @throws Error if refresh fails.\n */\n async refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string, resource: string, allowLoopback = false): Promise<TokenSet> {\n // See exchangeCodeForTokens - tokenEndpoint is remote-controlled discovery data.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n resource,\n }),\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token refresh response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || refreshToken, // Reuse old refresh token if not provided\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Open browser to authorization URL\n * Uses platform-specific command to open default browser\n */\n private async openBrowser(url: string): Promise<void> {\n // Determine platform-specific command\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (platform === 'win32') {\n command = 'cmd';\n args = ['/c', 'start', url];\n } else {\n // Linux and others\n command = 'xdg-open';\n args = [url];\n }\n\n // Spawn browser process\n const child = child_process.spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n }\n}\n"],"names":["child_process","logger","defaultLogger","discoveryFetch","OAuthCallbackListener","generatePkce","InteractiveOAuthFlow","performAuthFlow","authorizationEndpoint","tokenEndpoint","clientId","clientSecret","options","callbackListener","port","pkce","debug","start","redirectUri","authUrl","URL","searchParams","set","scopes","length","join","resource","codeChallenge","codeChallengeMethod","headless","info","toString","openBrowser","timeout","result","waitForCallback","assertResponseIssuer","iss","tokens","exchangeCodeForTokens","code","allowLoopback","codeVerifier","error","Error","message","String","stop","undefined","issuer","authorizationResponseIssSupported","params","URLSearchParams","grant_type","redirect_uri","client_id","client_secret","response","method","headers","Accept","Connection","body","ok","errorText","text","status","data","json","access_token","tokenSet","accessToken","refreshToken","refresh_token","expiresAt","Date","now","expires_in","scope","split","refreshTokens","url","platform","process","command","args","child","spawn","detached","stdio","unref"],"mappings":"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"}
@@ -49,6 +49,7 @@ import { logger as defaultLogger } from '../utils/logger.js';
49
49
  */ handleCallback(url, res) {
50
50
  const code = url.searchParams.get('code');
51
51
  const state = url.searchParams.get('state');
52
+ const iss = url.searchParams.get('iss');
52
53
  const error = url.searchParams.get('error');
53
54
  const errorDescription = url.searchParams.get('error_description');
54
55
  // Handle OAuth errors
@@ -114,6 +115,9 @@ import { logger as defaultLogger } from '../utils/logger.js';
114
115
  if (state) {
115
116
  result.state = state;
116
117
  }
118
+ if (iss) {
119
+ result.iss = iss;
120
+ }
117
121
  this.resolveCallback(result);
118
122
  }
119
123
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/oauth-callback-listener.ts"],"sourcesContent":["/**\n * OAuth Callback Server for CLI Authentication\n * Listens for OAuth authorization callbacks and captures authorization code\n */\n\nimport http from 'node:http';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport type { CallbackResult } from './types.ts';\n\nexport interface OAuthCallbackListenerOptions {\n /** Port to listen on (required - use get-port package to find available port) */\n port: number;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: Logger;\n}\n\n/**\n * OAuthCallbackListener handles OAuth redirect callbacks\n * Starts a temporary HTTP server to receive authorization code\n *\n * Note: Caller is responsible for finding an available port using get-port package\n */\nexport class OAuthCallbackListener {\n private server: http.Server | undefined;\n private resolveCallback?: (result: CallbackResult) => void;\n private rejectCallback?: (error: Error) => void;\n private timeout: NodeJS.Timeout | undefined;\n private port: number;\n private logger: Logger;\n\n constructor(options: OAuthCallbackListenerOptions) {\n this.port = options.port;\n this.logger = options.logger ?? defaultLogger;\n }\n\n /**\n * Start the callback server\n * Fails fast if port is already in use - caller should use get-port to find available port\n */\n async start(): Promise<void> {\n await this.listen(this.port);\n this.logger.debug(`✅ Callback server listening on http://localhost:${this.port}/callback`);\n }\n\n /**\n * Listen on a specific port\n */\n private listen(port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n this.server.on('error', (error) => {\n reject(error);\n });\n\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n /**\n * Handle incoming HTTP requests\n */\n private handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n const url = new URL(req.url || '', `http://localhost:${this.port}`);\n\n if (url.pathname === '/callback') {\n this.handleCallback(url, res);\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n }\n\n /**\n * Handle OAuth callback\n */\n private handleCallback(url: URL, res: http.ServerResponse): void {\n const code = url.searchParams.get('code');\n const state = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n // Handle OAuth errors\n if (error) {\n const errorMessage = errorDescription ? `${error}: ${errorDescription}` : error;\n\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <h1>Authorization Failed</h1>\n <p>${errorMessage}</p>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n\n if (this.rejectCallback) {\n this.rejectCallback(new Error(errorMessage));\n }\n return;\n }\n\n // Validate code parameter\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <h1>Invalid Callback</h1>\n <p>Missing authorization code</p>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n\n if (this.rejectCallback) {\n this.rejectCallback(new Error('Missing authorization code'));\n }\n return;\n }\n\n // Success - send confirmation page\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n </head>\n <body>\n <h1>Authorization Successful</h1>\n <p>You can close this window and return to the terminal.</p>\n <script>setTimeout(() => window.close(), 2000);</script>\n </body>\n </html>\n `);\n\n // Resolve the promise with authorization code\n if (this.resolveCallback) {\n const result: CallbackResult = { code };\n if (state) {\n result.state = state;\n }\n this.resolveCallback(result);\n }\n }\n\n /**\n * Wait for OAuth callback with timeout\n */\n async waitForCallback(timeoutMs = 300000): Promise<CallbackResult> {\n return new Promise((resolve, reject) => {\n this.resolveCallback = resolve;\n this.rejectCallback = reject;\n\n // Set timeout to prevent hanging forever\n this.timeout = setTimeout(() => {\n reject(new Error(`Authorization timeout - no callback received within ${timeoutMs / 1000} seconds`));\n this.stop();\n }, timeoutMs);\n });\n }\n\n /**\n * Stop the callback server and close\n */\n async stop(): Promise<void> {\n // Clear the timeout\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n\n // Close the server\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server?.close(() => {\n this.logger.debug('🔒 Callback server closed');\n resolve();\n });\n });\n this.server = undefined;\n }\n }\n\n /**\n * Get the callback URL for this server\n */\n getCallbackUrl(): string {\n if (!this.port) {\n throw new Error('Server not started - call start() first');\n }\n return `http://localhost:${this.port}/callback`;\n }\n}\n"],"names":["http","logger","defaultLogger","OAuthCallbackListener","start","listen","port","debug","Promise","resolve","reject","server","createServer","req","res","handleRequest","on","error","url","URL","pathname","handleCallback","writeHead","end","code","searchParams","get","state","errorDescription","errorMessage","rejectCallback","Error","resolveCallback","result","waitForCallback","timeoutMs","timeout","setTimeout","stop","clearTimeout","undefined","close","getCallbackUrl","options"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/oauth-callback-listener.ts"],"sourcesContent":["/**\n * OAuth Callback Server for CLI Authentication\n * Listens for OAuth authorization callbacks and captures authorization code\n */\n\nimport http from 'node:http';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport type { CallbackResult } from './types.ts';\n\nexport interface OAuthCallbackListenerOptions {\n /** Port to listen on (required - use get-port package to find available port) */\n port: number;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: Logger;\n}\n\n/**\n * OAuthCallbackListener handles OAuth redirect callbacks\n * Starts a temporary HTTP server to receive authorization code\n *\n * Note: Caller is responsible for finding an available port using get-port package\n */\nexport class OAuthCallbackListener {\n private server: http.Server | undefined;\n private resolveCallback?: (result: CallbackResult) => void;\n private rejectCallback?: (error: Error) => void;\n private timeout: NodeJS.Timeout | undefined;\n private port: number;\n private logger: Logger;\n\n constructor(options: OAuthCallbackListenerOptions) {\n this.port = options.port;\n this.logger = options.logger ?? defaultLogger;\n }\n\n /**\n * Start the callback server\n * Fails fast if port is already in use - caller should use get-port to find available port\n */\n async start(): Promise<void> {\n await this.listen(this.port);\n this.logger.debug(`✅ Callback server listening on http://localhost:${this.port}/callback`);\n }\n\n /**\n * Listen on a specific port\n */\n private listen(port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n this.server.on('error', (error) => {\n reject(error);\n });\n\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n /**\n * Handle incoming HTTP requests\n */\n private handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n const url = new URL(req.url || '', `http://localhost:${this.port}`);\n\n if (url.pathname === '/callback') {\n this.handleCallback(url, res);\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n }\n\n /**\n * Handle OAuth callback\n */\n private handleCallback(url: URL, res: http.ServerResponse): void {\n const code = url.searchParams.get('code');\n const state = url.searchParams.get('state');\n const iss = url.searchParams.get('iss');\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n // Handle OAuth errors\n if (error) {\n const errorMessage = errorDescription ? `${error}: ${errorDescription}` : error;\n\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <h1>Authorization Failed</h1>\n <p>${errorMessage}</p>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n\n if (this.rejectCallback) {\n this.rejectCallback(new Error(errorMessage));\n }\n return;\n }\n\n // Validate code parameter\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <h1>Invalid Callback</h1>\n <p>Missing authorization code</p>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n\n if (this.rejectCallback) {\n this.rejectCallback(new Error('Missing authorization code'));\n }\n return;\n }\n\n // Success - send confirmation page\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n </head>\n <body>\n <h1>Authorization Successful</h1>\n <p>You can close this window and return to the terminal.</p>\n <script>setTimeout(() => window.close(), 2000);</script>\n </body>\n </html>\n `);\n\n // Resolve the promise with authorization code\n if (this.resolveCallback) {\n const result: CallbackResult = { code };\n if (state) {\n result.state = state;\n }\n if (iss) {\n result.iss = iss;\n }\n this.resolveCallback(result);\n }\n }\n\n /**\n * Wait for OAuth callback with timeout\n */\n async waitForCallback(timeoutMs = 300000): Promise<CallbackResult> {\n return new Promise((resolve, reject) => {\n this.resolveCallback = resolve;\n this.rejectCallback = reject;\n\n // Set timeout to prevent hanging forever\n this.timeout = setTimeout(() => {\n reject(new Error(`Authorization timeout - no callback received within ${timeoutMs / 1000} seconds`));\n this.stop();\n }, timeoutMs);\n });\n }\n\n /**\n * Stop the callback server and close\n */\n async stop(): Promise<void> {\n // Clear the timeout\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n\n // Close the server\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server?.close(() => {\n this.logger.debug('🔒 Callback server closed');\n resolve();\n });\n });\n this.server = undefined;\n }\n }\n\n /**\n * Get the callback URL for this server\n */\n getCallbackUrl(): string {\n if (!this.port) {\n throw new Error('Server not started - call start() first');\n }\n return `http://localhost:${this.port}/callback`;\n }\n}\n"],"names":["http","logger","defaultLogger","OAuthCallbackListener","start","listen","port","debug","Promise","resolve","reject","server","createServer","req","res","handleRequest","on","error","url","URL","pathname","handleCallback","writeHead","end","code","searchParams","get","state","iss","errorDescription","errorMessage","rejectCallback","Error","resolveCallback","result","waitForCallback","timeoutMs","timeout","setTimeout","stop","clearTimeout","undefined","close","getCallbackUrl","options"],"mappings":"AAAA;;;CAGC,GAED,OAAOA,UAAU,YAAY;AAC7B,SAASC,UAAUC,aAAa,QAAqB,qBAAqB;AAU1E;;;;;CAKC,GACD,OAAO,MAAMC;IAaX;;;GAGC,GACD,MAAMC,QAAuB;QAC3B,MAAM,IAAI,CAACC,MAAM,CAAC,IAAI,CAACC,IAAI;QAC3B,IAAI,CAACL,MAAM,CAACM,KAAK,CAAC,CAAC,gDAAgD,EAAE,IAAI,CAACD,IAAI,CAAC,SAAS,CAAC;IAC3F;IAEA;;GAEC,GACD,AAAQD,OAAOC,IAAY,EAAiB;QAC1C,OAAO,IAAIE,QAAQ,CAACC,SAASC;YAC3B,IAAI,CAACC,MAAM,GAAGX,KAAKY,YAAY,CAAC,CAACC,KAAKC;gBACpC,IAAI,CAACC,aAAa,CAACF,KAAKC;YAC1B;YAEA,IAAI,CAACH,MAAM,CAACK,EAAE,CAAC,SAAS,CAACC;gBACvBP,OAAOO;YACT;YAEA,IAAI,CAACN,MAAM,CAACN,MAAM,CAACC,MAAM;gBACvBG;YACF;QACF;IACF;IAEA;;GAEC,GACD,AAAQM,cAAcF,GAAyB,EAAEC,GAAwB,EAAQ;QAC/E,MAAMI,MAAM,IAAIC,IAAIN,IAAIK,GAAG,IAAI,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAACZ,IAAI,EAAE;QAElE,IAAIY,IAAIE,QAAQ,KAAK,aAAa;YAChC,IAAI,CAACC,cAAc,CAACH,KAAKJ;QAC3B,OAAO;YACLA,IAAIQ,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAa;YAClDR,IAAIS,GAAG,CAAC;QACV;IACF;IAEA;;GAEC,GACD,AAAQF,eAAeH,GAAQ,EAAEJ,GAAwB,EAAQ;QAC/D,MAAMU,OAAON,IAAIO,YAAY,CAACC,GAAG,CAAC;QAClC,MAAMC,QAAQT,IAAIO,YAAY,CAACC,GAAG,CAAC;QACnC,MAAME,MAAMV,IAAIO,YAAY,CAACC,GAAG,CAAC;QACjC,MAAMT,QAAQC,IAAIO,YAAY,CAACC,GAAG,CAAC;QACnC,MAAMG,mBAAmBX,IAAIO,YAAY,CAACC,GAAG,CAAC;QAE9C,sBAAsB;QACtB,IAAIT,OAAO;YACT,MAAMa,eAAeD,mBAAmB,GAAGZ,MAAM,EAAE,EAAEY,kBAAkB,GAAGZ;YAE1EH,IAAIQ,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAY;YACjDR,IAAIS,GAAG,CAAC,CAAC;;;;eAIA,EAAEO,aAAa;;;;MAIxB,CAAC;YAED,IAAI,IAAI,CAACC,cAAc,EAAE;gBACvB,IAAI,CAACA,cAAc,CAAC,IAAIC,MAAMF;YAChC;YACA;QACF;QAEA,0BAA0B;QAC1B,IAAI,CAACN,MAAM;YACTV,IAAIQ,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAY;YACjDR,IAAIS,GAAG,CAAC,CAAC;;;;;;;;MAQT,CAAC;YAED,IAAI,IAAI,CAACQ,cAAc,EAAE;gBACvB,IAAI,CAACA,cAAc,CAAC,IAAIC,MAAM;YAChC;YACA;QACF;QAEA,mCAAmC;QACnClB,IAAIQ,SAAS,CAAC,KAAK;YAAE,gBAAgB;QAA2B;QAChER,IAAIS,GAAG,CAAC,CAAC;;;;;;;;;;;IAWT,CAAC;QAED,8CAA8C;QAC9C,IAAI,IAAI,CAACU,eAAe,EAAE;YACxB,MAAMC,SAAyB;gBAAEV;YAAK;YACtC,IAAIG,OAAO;gBACTO,OAAOP,KAAK,GAAGA;YACjB;YACA,IAAIC,KAAK;gBACPM,OAAON,GAAG,GAAGA;YACf;YACA,IAAI,CAACK,eAAe,CAACC;QACvB;IACF;IAEA;;GAEC,GACD,MAAMC,gBAAgBC,YAAY,MAAM,EAA2B;QACjE,OAAO,IAAI5B,QAAQ,CAACC,SAASC;YAC3B,IAAI,CAACuB,eAAe,GAAGxB;YACvB,IAAI,CAACsB,cAAc,GAAGrB;YAEtB,yCAAyC;YACzC,IAAI,CAAC2B,OAAO,GAAGC,WAAW;gBACxB5B,OAAO,IAAIsB,MAAM,CAAC,oDAAoD,EAAEI,YAAY,KAAK,QAAQ,CAAC;gBAClG,IAAI,CAACG,IAAI;YACX,GAAGH;QACL;IACF;IAEA;;GAEC,GACD,MAAMG,OAAsB;QAC1B,oBAAoB;QACpB,IAAI,IAAI,CAACF,OAAO,EAAE;YAChBG,aAAa,IAAI,CAACH,OAAO;YACzB,IAAI,CAACA,OAAO,GAAGI;QACjB;QAEA,mBAAmB;QACnB,IAAI,IAAI,CAAC9B,MAAM,EAAE;YACf,MAAM,IAAIH,QAAc,CAACC;oBACvB;iBAAA,eAAA,IAAI,CAACE,MAAM,cAAX,mCAAA,aAAa+B,KAAK,CAAC;oBACjB,IAAI,CAACzC,MAAM,CAACM,KAAK,CAAC;oBAClBE;gBACF;YACF;YACA,IAAI,CAACE,MAAM,GAAG8B;QAChB;IACF;IAEA;;GAEC,GACDE,iBAAyB;QACvB,IAAI,CAAC,IAAI,CAACrC,IAAI,EAAE;YACd,MAAM,IAAI0B,MAAM;QAClB;QACA,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC1B,IAAI,CAAC,SAAS,CAAC;IACjD;IA3KA,YAAYsC,OAAqC,CAAE;YAEnCA;QADd,IAAI,CAACtC,IAAI,GAAGsC,QAAQtC,IAAI;QACxB,IAAI,CAACL,MAAM,IAAG2C,kBAAAA,QAAQ3C,MAAM,cAAd2C,6BAAAA,kBAAkB1C;IAClC;AAyKF"}
@@ -9,6 +9,8 @@ export interface CallbackResult {
9
9
  code: string;
10
10
  /** State parameter for CSRF protection */
11
11
  state?: string;
12
+ /** Issuer identifier of the authorization server that minted the response (RFC 9207) */
13
+ iss?: string;
12
14
  }
13
15
  /**
14
16
  * PKCE (Proof Key for Code Exchange) parameters (RFC 7636)
@@ -38,6 +40,8 @@ export interface TokenSet {
38
40
  clientId?: string;
39
41
  /** Client secret used for DCR registration (stored for future use) */
40
42
  clientSecret?: string;
43
+ /** Issuer identifier of the authorization server these credentials belong to (SEP-2352) */
44
+ issuer?: string;
41
45
  }
42
46
  /**
43
47
  * OAuth 2.0 Protected Resource Metadata (RFC 9728)
@@ -76,6 +80,8 @@ export interface AuthorizationServerMetadata {
76
80
  grant_types_supported?: string[];
77
81
  /** Token endpoint authentication methods supported */
78
82
  token_endpoint_auth_methods_supported?: string[];
83
+ /** Whether the authorization response carries an `iss` parameter (RFC 9207) */
84
+ authorization_response_iss_parameter_supported?: boolean;
79
85
  }
80
86
  /**
81
87
  * OAuth server capabilities discovered from .well-known endpoint
@@ -83,6 +89,21 @@ export interface AuthorizationServerMetadata {
83
89
  export interface AuthCapabilities {
84
90
  /** Whether the server supports Dynamic Client Registration (RFC 7591) */
85
91
  supportsDcr: boolean;
92
+ /** Issuer identifier from the authorization server metadata (RFC 8414) */
93
+ issuer?: string;
94
+ /**
95
+ * The protected resource's canonical identifier, from the RFC 9728 metadata
96
+ * document's `resource` field. This is what an RFC 8707 `resource` indicator
97
+ * must carry, and it is the resource server's own statement of its identity -
98
+ * not the URL we happened to dial, and never the base URL discovery was
99
+ * performed against, which has any `/mcp` segment stripped off it.
100
+ *
101
+ * Absent when no protected-resource metadata was published and the
102
+ * authorization server was reached by direct RFC 8414 discovery instead.
103
+ */
104
+ resource?: string;
105
+ /** Whether the authorization response carries an `iss` parameter (RFC 9207) */
106
+ authorizationResponseIssSupported?: boolean;
86
107
  /** DCR client registration endpoint */
87
108
  registrationEndpoint?: string;
88
109
  /** OAuth authorization endpoint */
@@ -109,10 +130,10 @@ export interface ClientCredentials {
109
130
  * Options for DCR client registration
110
131
  */
111
132
  export interface DcrRegistrationOptions {
133
+ /** Redirect URI for OAuth callback, from the loopback listener the caller has already bound (RFC 8252) */
134
+ redirectUri: string;
112
135
  /** Client name to register */
113
136
  clientName?: string;
114
- /** Redirect URI for OAuth callback */
115
- redirectUri?: string;
116
137
  /**
117
138
  * Loopback trust grant for the registration_endpoint fetch (SSRF
118
139
  * mitigation - see `src/auth/discovery-fetch.ts`). Compute this from the
@@ -128,12 +149,16 @@ export interface DcrRegistrationOptions {
128
149
  export interface OAuthFlowOptions {
129
150
  /** Port for OAuth callback listener (required - use get-port to find available port) */
130
151
  port: number;
152
+ /** Issuer identifier discovered before the flow starts; the `iss` in the authorization response must match it (RFC 9207) */
153
+ issuer: string;
154
+ /** Canonical resource server URI, sent as `resource` on the authorization, token, and refresh requests (RFC 8707) */
155
+ resource: string;
131
156
  /** Redirect URI for OAuth callback (optional - will be built from port if not provided) */
132
157
  redirectUri?: string;
133
158
  /** OAuth scopes to request */
134
159
  scopes?: string[];
135
- /** Resource parameter (RFC 8707) - target resource server identifier */
136
- resource?: string;
160
+ /** Whether the authorization server advertises `authorization_response_iss_parameter_supported` (RFC 9207) */
161
+ authorizationResponseIssSupported?: boolean;
137
162
  /** Enable PKCE (RFC 7636) - recommended for all clients, required for public clients */
138
163
  pkce?: boolean;
139
164
  /** Headless mode (don't open browser) */
@@ -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}\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}\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}\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 /** 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 /** Client name to register */\n clientName?: string;\n /** Redirect URI for OAuth callback */\n redirectUri?: 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 /** 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 /** Resource parameter (RFC 8707) - target resource server identifier */\n resource?: string;\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,GA+HD;;CAEC,GACD,WAyBC"}
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,GAoJD;;CAEC,GACD,WA6BC"}
@@ -1,5 +1,4 @@
1
- import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
- import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
1
+ import type { Client } from '@modelcontextprotocol/client';
3
2
  import type { ToolArguments } from './connection/types.js';
4
3
  import { PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } from './response-wrappers.js';
5
4
  export type PromptArguments = Record<string, string>;
@@ -33,10 +32,10 @@ export type ManagedClient = Omit<Client, 'callTool' | 'getPrompt' | 'readResourc
33
32
  readonly serverName: string;
34
33
  /** Underlying MCP SDK client for advanced scenarios. */
35
34
  readonly nativeClient: Client;
36
- callTool(toolName: string, args?: ToolArguments, requestOptions?: RequestOptions): WrappedCallToolReturn;
37
- callTool(invocation: NativeCallToolParams[0], sessionId?: NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]): WrappedCallToolReturn;
38
- callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: RequestOptions): NativeCallToolReturn;
39
- callToolRaw(invocation: NativeCallToolParams[0], sessionId?: NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]): NativeCallToolReturn;
35
+ callTool(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;
36
+ callTool(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;
37
+ callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;
38
+ callToolRaw(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;
40
39
  getPrompt(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;
41
40
  getPrompt(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;
42
41
  getPromptRaw(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;
@@ -17,23 +17,23 @@ import { PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } f
17
17
  });
18
18
  const nativeCallTool = client.callTool.bind(client);
19
19
  const wrapCallTool = (promise)=>promise.then((payload)=>new ToolResponseWrapper(payload));
20
- enhanced.callTool = (nameOrInvocation, argsOrSession, requestOptions)=>{
20
+ enhanced.callTool = (nameOrInvocation, argsOrOptions, requestOptions)=>{
21
21
  if (typeof nameOrInvocation === 'string') {
22
22
  return wrapCallTool(nativeCallTool({
23
23
  name: nameOrInvocation,
24
- arguments: argsOrSession !== null && argsOrSession !== void 0 ? argsOrSession : {}
25
- }, undefined, requestOptions));
24
+ arguments: argsOrOptions !== null && argsOrOptions !== void 0 ? argsOrOptions : {}
25
+ }, requestOptions));
26
26
  }
27
- return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrSession, requestOptions));
27
+ return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrOptions));
28
28
  };
29
- enhanced.callToolRaw = (nameOrInvocation, argsOrSession, requestOptions)=>{
29
+ enhanced.callToolRaw = (nameOrInvocation, argsOrOptions, requestOptions)=>{
30
30
  if (typeof nameOrInvocation === 'string') {
31
31
  return nativeCallTool({
32
32
  name: nameOrInvocation,
33
- arguments: argsOrSession !== null && argsOrSession !== void 0 ? argsOrSession : {}
34
- }, undefined, requestOptions);
33
+ arguments: argsOrOptions !== null && argsOrOptions !== void 0 ? argsOrOptions : {}
34
+ }, requestOptions);
35
35
  }
36
- return nativeCallTool(nameOrInvocation, argsOrSession, requestOptions);
36
+ return nativeCallTool(nameOrInvocation, argsOrOptions);
37
37
  };
38
38
  const nativeGetPrompt = client.getPrompt.bind(client);
39
39
  const wrapPrompt = (promise)=>promise.then((payload)=>new PromptResponseWrapper(payload));
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/client-helpers.ts"],"sourcesContent":["import type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';\nimport type { ToolArguments } from './connection/types.ts';\nimport { type NativeCallToolResponse, type NativeGetPromptResponse, type NativeReadResourceResponse, PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } from './response-wrappers.ts';\n\nexport type PromptArguments = Record<string, string>;\n\ntype NativeCallToolParams = Parameters<Client['callTool']>;\ntype NativeCallToolReturn = ReturnType<Client['callTool']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.callTool()`.\n * @public\n */\nexport type WrappedCallToolReturn = Promise<ToolResponseWrapper>;\n\ntype NativeGetPromptParams = Parameters<Client['getPrompt']>;\ntype NativeGetPromptReturn = ReturnType<Client['getPrompt']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.getPrompt()`.\n * @public\n */\nexport type WrappedGetPromptReturn = Promise<PromptResponseWrapper>;\n\ntype NativeReadResourceParams = Parameters<Client['readResource']>;\ntype NativeReadResourceReturn = ReturnType<Client['readResource']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.readResource()`.\n * @public\n */\nexport type WrappedReadResourceReturn = Promise<ResourceResponseWrapper>;\n\n/**\n * Client returned by registry.connect() with convenience overloads for\n * calling tools, reading resources, and getting prompts using simple arguments.\n */\nexport type ManagedClient = Omit<Client, 'callTool' | 'getPrompt' | 'readResource'> & {\n /** Name of the server this client is connected to. */\n readonly serverName: string;\n /** Underlying MCP SDK client for advanced scenarios. */\n readonly nativeClient: Client;\n\n callTool(toolName: string, args?: ToolArguments, requestOptions?: RequestOptions): WrappedCallToolReturn;\n callTool(invocation: NativeCallToolParams[0], sessionId?: NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]): WrappedCallToolReturn;\n callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: RequestOptions): NativeCallToolReturn;\n callToolRaw(invocation: NativeCallToolParams[0], sessionId?: NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]): NativeCallToolReturn;\n\n getPrompt(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPrompt(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPromptRaw(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n getPromptRaw(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n\n readResource(uri: string, requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResource(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResourceRaw(uri: string, requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n readResourceRaw(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n};\n\n/**\n * Enhance an MCP SDK client with convenience overloads.\n */\nexport function decorateClient(client: Client, metadata: { serverName: string }): ManagedClient {\n const enhanced = client as unknown as ManagedClient;\n\n Object.defineProperty(enhanced, 'serverName', {\n value: metadata.serverName,\n enumerable: true,\n configurable: false,\n writable: false,\n });\n Object.defineProperty(enhanced, 'nativeClient', {\n value: client,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n\n const nativeCallTool = client.callTool.bind(client);\n const wrapCallTool = (promise: NativeCallToolReturn): WrappedCallToolReturn => promise.then((payload) => new ToolResponseWrapper(payload as NativeCallToolResponse));\n\n enhanced.callTool = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrSession?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]) => {\n if (typeof nameOrInvocation === 'string') {\n return wrapCallTool(nativeCallTool({ name: nameOrInvocation, arguments: (argsOrSession as ToolArguments) ?? {} }, undefined, requestOptions));\n }\n return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrSession as NativeCallToolParams[1], requestOptions));\n }) as ManagedClient['callTool'];\n\n enhanced.callToolRaw = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrSession?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[2]) => {\n if (typeof nameOrInvocation === 'string') {\n return nativeCallTool({ name: nameOrInvocation, arguments: (argsOrSession as ToolArguments) ?? {} }, undefined, requestOptions);\n }\n return nativeCallTool(nameOrInvocation, argsOrSession as NativeCallToolParams[1], requestOptions);\n }) as ManagedClient['callToolRaw'];\n\n const nativeGetPrompt = client.getPrompt.bind(client);\n const wrapPrompt = (promise: NativeGetPromptReturn): WrappedGetPromptReturn => promise.then((payload) => new PromptResponseWrapper(payload as NativeGetPromptResponse));\n\n enhanced.getPrompt = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return wrapPrompt(nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions));\n }\n return wrapPrompt(nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]));\n }) as ManagedClient['getPrompt'];\n\n enhanced.getPromptRaw = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions);\n }\n return nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]);\n }) as ManagedClient['getPromptRaw'];\n\n const nativeReadResource = client.readResource.bind(client);\n const wrapResource = (promise: NativeReadResourceReturn): WrappedReadResourceReturn => promise.then((payload) => new ResourceResponseWrapper(payload as NativeReadResourceResponse));\n\n enhanced.readResource = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return wrapResource(nativeReadResource({ uri: uriOrRequest }, requestOptions));\n }\n return wrapResource(nativeReadResource(uriOrRequest, requestOptions));\n }) as ManagedClient['readResource'];\n\n enhanced.readResourceRaw = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return nativeReadResource({ uri: uriOrRequest }, requestOptions);\n }\n return nativeReadResource(uriOrRequest, requestOptions);\n }) as ManagedClient['readResourceRaw'];\n\n return enhanced;\n}\n"],"names":["PromptResponseWrapper","ResourceResponseWrapper","ToolResponseWrapper","decorateClient","client","metadata","enhanced","Object","defineProperty","value","serverName","enumerable","configurable","writable","nativeCallTool","callTool","bind","wrapCallTool","promise","then","payload","nameOrInvocation","argsOrSession","requestOptions","name","arguments","undefined","callToolRaw","nativeGetPrompt","getPrompt","wrapPrompt","nameOrParams","argsOrOptions","getPromptRaw","nativeReadResource","readResource","wrapResource","uriOrRequest","uri","readResourceRaw"],"mappings":"AAGA,SAAqGA,qBAAqB,EAAEC,uBAAuB,EAAEC,mBAAmB,QAAQ,yBAAyB;AAsDzM;;CAEC,GACD,OAAO,SAASC,eAAeC,MAAc,EAAEC,QAAgC;IAC7E,MAAMC,WAAWF;IAEjBG,OAAOC,cAAc,CAACF,UAAU,cAAc;QAC5CG,OAAOJ,SAASK,UAAU;QAC1BC,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IACAN,OAAOC,cAAc,CAACF,UAAU,gBAAgB;QAC9CG,OAAOL;QACPO,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IAEA,MAAMC,iBAAiBV,OAAOW,QAAQ,CAACC,IAAI,CAACZ;IAC5C,MAAMa,eAAe,CAACC,UAAyDA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIlB,oBAAoBkB;IAEjId,SAASS,QAAQ,GAAI,CAACM,kBAAoDC,eAAyDC;QACjI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOJ,aAAaH,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGI,WAAWH;QAC/H;QACA,OAAON,aAAaH,eAAeO,kBAAkBC,eAA0CC;IACjG;IAEAjB,SAASqB,WAAW,GAAI,CAACN,kBAAoDC,eAAyDC;QACpI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOP,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGI,WAAWH;QAClH;QACA,OAAOT,eAAeO,kBAAkBC,eAA0CC;IACpF;IAEA,MAAMK,kBAAkBxB,OAAOyB,SAAS,CAACb,IAAI,CAACZ;IAC9C,MAAM0B,aAAa,CAACZ,UAA2DA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIpB,sBAAsBoB;IAEnId,SAASuB,SAAS,GAAI,CAACE,cAAiDC,eAA4DT;QAClI,IAAI,OAAOQ,iBAAiB,UAAU;YACpC,OAAOD,WAAWF,gBAAgB;gBAAEJ,MAAMO;gBAAc,GAAIC,gBAAgB;oBAAEP,WAAWO;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGT;QACvI;QACA,OAAOO,WAAWF,gBAAgBG,cAAcC;IAClD;IAEA1B,SAAS2B,YAAY,GAAI,CAACF,cAAiDC,eAA4DT;QACrI,IAAI,OAAOQ,iBAAiB,UAAU;YACpC,OAAOH,gBAAgB;gBAAEJ,MAAMO;gBAAc,GAAIC,gBAAgB;oBAAEP,WAAWO;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGT;QAC5H;QACA,OAAOK,gBAAgBG,cAAcC;IACvC;IAEA,MAAME,qBAAqB9B,OAAO+B,YAAY,CAACnB,IAAI,CAACZ;IACpD,MAAMgC,eAAe,CAAClB,UAAiEA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAInB,wBAAwBmB;IAE7Id,SAAS6B,YAAY,GAAI,CAACE,cAAoDd;QAC5E,IAAI,OAAOc,iBAAiB,UAAU;YACpC,OAAOD,aAAaF,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGd;QAChE;QACA,OAAOa,aAAaF,mBAAmBG,cAAcd;IACvD;IAEAjB,SAASiC,eAAe,GAAI,CAACF,cAAoDd;QAC/E,IAAI,OAAOc,iBAAiB,UAAU;YACpC,OAAOH,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGd;QACnD;QACA,OAAOW,mBAAmBG,cAAcd;IAC1C;IAEA,OAAOjB;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/client-helpers.ts"],"sourcesContent":["import type { Client } from '@modelcontextprotocol/client';\nimport type { ToolArguments } from './connection/types.ts';\nimport { type NativeCallToolResponse, type NativeGetPromptResponse, type NativeReadResourceResponse, PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } from './response-wrappers.ts';\n\nexport type PromptArguments = Record<string, string>;\n\ntype NativeCallToolParams = Parameters<Client['callTool']>;\ntype NativeCallToolReturn = ReturnType<Client['callTool']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.callTool()`.\n * @public\n */\nexport type WrappedCallToolReturn = Promise<ToolResponseWrapper>;\n\ntype NativeGetPromptParams = Parameters<Client['getPrompt']>;\ntype NativeGetPromptReturn = ReturnType<Client['getPrompt']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.getPrompt()`.\n * @public\n */\nexport type WrappedGetPromptReturn = Promise<PromptResponseWrapper>;\n\ntype NativeReadResourceParams = Parameters<Client['readResource']>;\ntype NativeReadResourceReturn = ReturnType<Client['readResource']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.readResource()`.\n * @public\n */\nexport type WrappedReadResourceReturn = Promise<ResourceResponseWrapper>;\n\n/**\n * Client returned by registry.connect() with convenience overloads for\n * calling tools, reading resources, and getting prompts using simple arguments.\n */\nexport type ManagedClient = Omit<Client, 'callTool' | 'getPrompt' | 'readResource'> & {\n /** Name of the server this client is connected to. */\n readonly serverName: string;\n /** Underlying MCP SDK client for advanced scenarios. */\n readonly nativeClient: Client;\n\n callTool(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;\n callTool(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;\n callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;\n callToolRaw(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;\n\n getPrompt(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPrompt(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPromptRaw(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n getPromptRaw(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n\n readResource(uri: string, requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResource(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResourceRaw(uri: string, requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n readResourceRaw(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n};\n\n/**\n * Enhance an MCP SDK client with convenience overloads.\n */\nexport function decorateClient(client: Client, metadata: { serverName: string }): ManagedClient {\n const enhanced = client as unknown as ManagedClient;\n\n Object.defineProperty(enhanced, 'serverName', {\n value: metadata.serverName,\n enumerable: true,\n configurable: false,\n writable: false,\n });\n Object.defineProperty(enhanced, 'nativeClient', {\n value: client,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n\n const nativeCallTool = client.callTool.bind(client);\n const wrapCallTool = (promise: NativeCallToolReturn): WrappedCallToolReturn => promise.then((payload) => new ToolResponseWrapper(payload as NativeCallToolResponse));\n\n enhanced.callTool = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrOptions?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[1]) => {\n if (typeof nameOrInvocation === 'string') {\n return wrapCallTool(nativeCallTool({ name: nameOrInvocation, arguments: (argsOrOptions as ToolArguments) ?? {} }, requestOptions));\n }\n return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrOptions as NativeCallToolParams[1]));\n }) as ManagedClient['callTool'];\n\n enhanced.callToolRaw = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrOptions?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[1]) => {\n if (typeof nameOrInvocation === 'string') {\n return nativeCallTool({ name: nameOrInvocation, arguments: (argsOrOptions as ToolArguments) ?? {} }, requestOptions);\n }\n return nativeCallTool(nameOrInvocation, argsOrOptions as NativeCallToolParams[1]);\n }) as ManagedClient['callToolRaw'];\n\n const nativeGetPrompt = client.getPrompt.bind(client);\n const wrapPrompt = (promise: NativeGetPromptReturn): WrappedGetPromptReturn => promise.then((payload) => new PromptResponseWrapper(payload as NativeGetPromptResponse));\n\n enhanced.getPrompt = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return wrapPrompt(nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions));\n }\n return wrapPrompt(nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]));\n }) as ManagedClient['getPrompt'];\n\n enhanced.getPromptRaw = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions);\n }\n return nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]);\n }) as ManagedClient['getPromptRaw'];\n\n const nativeReadResource = client.readResource.bind(client);\n const wrapResource = (promise: NativeReadResourceReturn): WrappedReadResourceReturn => promise.then((payload) => new ResourceResponseWrapper(payload as NativeReadResourceResponse));\n\n enhanced.readResource = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return wrapResource(nativeReadResource({ uri: uriOrRequest }, requestOptions));\n }\n return wrapResource(nativeReadResource(uriOrRequest, requestOptions));\n }) as ManagedClient['readResource'];\n\n enhanced.readResourceRaw = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return nativeReadResource({ uri: uriOrRequest }, requestOptions);\n }\n return nativeReadResource(uriOrRequest, requestOptions);\n }) as ManagedClient['readResourceRaw'];\n\n return enhanced;\n}\n"],"names":["PromptResponseWrapper","ResourceResponseWrapper","ToolResponseWrapper","decorateClient","client","metadata","enhanced","Object","defineProperty","value","serverName","enumerable","configurable","writable","nativeCallTool","callTool","bind","wrapCallTool","promise","then","payload","nameOrInvocation","argsOrOptions","requestOptions","name","arguments","callToolRaw","nativeGetPrompt","getPrompt","wrapPrompt","nameOrParams","getPromptRaw","nativeReadResource","readResource","wrapResource","uriOrRequest","uri","readResourceRaw"],"mappings":"AAEA,SAAqGA,qBAAqB,EAAEC,uBAAuB,EAAEC,mBAAmB,QAAQ,yBAAyB;AAsDzM;;CAEC,GACD,OAAO,SAASC,eAAeC,MAAc,EAAEC,QAAgC;IAC7E,MAAMC,WAAWF;IAEjBG,OAAOC,cAAc,CAACF,UAAU,cAAc;QAC5CG,OAAOJ,SAASK,UAAU;QAC1BC,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IACAN,OAAOC,cAAc,CAACF,UAAU,gBAAgB;QAC9CG,OAAOL;QACPO,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IAEA,MAAMC,iBAAiBV,OAAOW,QAAQ,CAACC,IAAI,CAACZ;IAC5C,MAAMa,eAAe,CAACC,UAAyDA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIlB,oBAAoBkB;IAEjId,SAASS,QAAQ,GAAI,CAACM,kBAAoDC,eAAyDC;QACjI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOJ,aAAaH,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGC;QACpH;QACA,OAAON,aAAaH,eAAeO,kBAAkBC;IACvD;IAEAhB,SAASoB,WAAW,GAAI,CAACL,kBAAoDC,eAAyDC;QACpI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOP,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGC;QACvG;QACA,OAAOT,eAAeO,kBAAkBC;IAC1C;IAEA,MAAMK,kBAAkBvB,OAAOwB,SAAS,CAACZ,IAAI,CAACZ;IAC9C,MAAMyB,aAAa,CAACX,UAA2DA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIpB,sBAAsBoB;IAEnId,SAASsB,SAAS,GAAI,CAACE,cAAiDR,eAA4DC;QAClI,IAAI,OAAOO,iBAAiB,UAAU;YACpC,OAAOD,WAAWF,gBAAgB;gBAAEH,MAAMM;gBAAc,GAAIR,gBAAgB;oBAAEG,WAAWH;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGC;QACvI;QACA,OAAOM,WAAWF,gBAAgBG,cAAcR;IAClD;IAEAhB,SAASyB,YAAY,GAAI,CAACD,cAAiDR,eAA4DC;QACrI,IAAI,OAAOO,iBAAiB,UAAU;YACpC,OAAOH,gBAAgB;gBAAEH,MAAMM;gBAAc,GAAIR,gBAAgB;oBAAEG,WAAWH;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGC;QAC5H;QACA,OAAOI,gBAAgBG,cAAcR;IACvC;IAEA,MAAMU,qBAAqB5B,OAAO6B,YAAY,CAACjB,IAAI,CAACZ;IACpD,MAAM8B,eAAe,CAAChB,UAAiEA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAInB,wBAAwBmB;IAE7Id,SAAS2B,YAAY,GAAI,CAACE,cAAoDZ;QAC5E,IAAI,OAAOY,iBAAiB,UAAU;YACpC,OAAOD,aAAaF,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGZ;QAChE;QACA,OAAOW,aAAaF,mBAAmBG,cAAcZ;IACvD;IAEAjB,SAAS+B,eAAe,GAAI,CAACF,cAAoDZ;QAC/E,IAAI,OAAOY,iBAAiB,UAAU;YACpC,OAAOH,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGZ;QACnD;QACA,OAAOS,mBAAmBG,cAAcZ;IAC1C;IAEA,OAAOjB;AACT"}
@@ -4,8 +4,8 @@
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 '../monkey-patches.js';
8
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
7
+ import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
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';
11
11
  import type { ServersConfig } from '../spawn/spawn-servers.js';
@@ -18,15 +18,6 @@ interface RegistryLike {
18
18
  servers: Map<string, ServerProcess>;
19
19
  }
20
20
  import { type Logger } from '../utils/logger.js';
21
- /**
22
- * Extract the "server base" by removing a trailing `/mcp` path segment if present.
23
- * Examples:
24
- * - https://example.com/mcp -> https://example.com
25
- * - https://example.com/sheets/mcp -> https://example.com/sheets
26
- * - https://example.com/sheets/mcp/ -> https://example.com/sheets
27
- * - https://example.com/sheets -> https://example.com/sheets
28
- */
29
- export declare function extractBaseUrl(mcpUrl: string): string;
30
21
  /**
31
22
  * Connect MCP SDK client to server with full readiness handling.
32
23
  * @internal - Use registry.connect() instead
@@ -42,6 +33,15 @@ export declare function extractBaseUrl(mcpUrl: string): string;
42
33
  *
43
34
  * @param registryOrConfig - Result from createServerRegistry() or servers config object
44
35
  * @param serverName - Server name from servers config
36
+ * @param options - Connection options (see below)
37
+ * @param options.dcrAuthenticator - DCR authenticator options
38
+ * @param options.logger - Logger for connection diagnostics
39
+ * @param options.versionNegotiation - SDK protocol version negotiation (protocol revision
40
+ * 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:
41
+ * the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and
42
+ * fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`
43
+ * to require the pinned revision (a server that cannot serve it fails the connect with
44
+ * a typed era-negotiation error).
45
45
  * @returns Connected MCP SDK Client (guaranteed ready)
46
46
  *
47
47
  * @example
@@ -64,5 +64,6 @@ export declare function extractBaseUrl(mcpUrl: string): string;
64
64
  export declare function connectMcpClient(registryOrConfig: RegistryLike | ServersConfig, serverName: string, options?: {
65
65
  dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
66
66
  logger?: Logger;
67
+ versionNegotiation?: VersionNegotiationOptions;
67
68
  }): Promise<Client>;
68
69
  export {};