@mcp-z/client 1.0.7 → 1.0.9

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 (88) hide show
  1. package/dist/cjs/auth/capability-discovery.js +2 -5
  2. package/dist/cjs/auth/capability-discovery.js.map +1 -1
  3. package/dist/cjs/auth/index.js.map +1 -1
  4. package/dist/cjs/auth/interactive-oauth-flow.js +13 -30
  5. package/dist/cjs/auth/interactive-oauth-flow.js.map +1 -1
  6. package/dist/cjs/auth/oauth-callback-listener.js +3 -8
  7. package/dist/cjs/auth/oauth-callback-listener.js.map +1 -1
  8. package/dist/cjs/auth/pkce.js +2 -5
  9. package/dist/cjs/auth/pkce.js.map +1 -1
  10. package/dist/cjs/auth/rfc9728-discovery.js +2 -5
  11. package/dist/cjs/auth/rfc9728-discovery.js.map +1 -1
  12. package/dist/cjs/auth/types.js.map +1 -1
  13. package/dist/cjs/client-helpers.js +4 -6
  14. package/dist/cjs/client-helpers.js.map +1 -1
  15. package/dist/cjs/config/server-loader.js +8 -19
  16. package/dist/cjs/config/server-loader.js.map +1 -1
  17. package/dist/cjs/config/validate-config.js +8 -19
  18. package/dist/cjs/config/validate-config.js.map +1 -1
  19. package/dist/cjs/connection/connect-client.js +5 -11
  20. package/dist/cjs/connection/connect-client.js.map +1 -1
  21. package/dist/cjs/connection/existing-process-transport.js +3 -8
  22. package/dist/cjs/connection/existing-process-transport.js.map +1 -1
  23. package/dist/cjs/connection/types.d.cts +1 -1
  24. package/dist/cjs/connection/types.d.ts +1 -1
  25. package/dist/cjs/connection/types.js.map +1 -1
  26. package/dist/cjs/connection/wait-for-http-ready.js +2 -5
  27. package/dist/cjs/connection/wait-for-http-ready.js.map +1 -1
  28. package/dist/cjs/constants.js.map +1 -1
  29. package/dist/cjs/dcr/dcr-authenticator.js +13 -30
  30. package/dist/cjs/dcr/dcr-authenticator.js.map +1 -1
  31. package/dist/cjs/dcr/dynamic-client-registrar.js +3 -8
  32. package/dist/cjs/dcr/dynamic-client-registrar.js.map +1 -1
  33. package/dist/cjs/dcr/index.js.map +1 -1
  34. package/dist/cjs/index.js.map +1 -1
  35. package/dist/cjs/lib/url-utils.js.map +1 -1
  36. package/dist/cjs/monkey-patches.js +11 -14
  37. package/dist/cjs/monkey-patches.js.map +1 -1
  38. package/dist/cjs/response-wrappers.js +24 -31
  39. package/dist/cjs/response-wrappers.js.map +1 -1
  40. package/dist/cjs/search/index.js.map +1 -1
  41. package/dist/cjs/search/search.js +15 -18
  42. package/dist/cjs/search/search.js.map +1 -1
  43. package/dist/cjs/search/types.js.map +1 -1
  44. package/dist/cjs/spawn/spawn-server.js +22 -38
  45. package/dist/cjs/spawn/spawn-server.js.map +1 -1
  46. package/dist/cjs/spawn/spawn-servers.js +29 -47
  47. package/dist/cjs/spawn/spawn-servers.js.map +1 -1
  48. package/dist/cjs/types.js.map +1 -1
  49. package/dist/cjs/utils/logger.js +1 -1
  50. package/dist/cjs/utils/logger.js.map +1 -1
  51. package/dist/cjs/utils/path-utils.js +9 -20
  52. package/dist/cjs/utils/path-utils.js.map +1 -1
  53. package/dist/cjs/utils/sanitizer.js +4 -7
  54. package/dist/cjs/utils/sanitizer.js.map +1 -1
  55. package/dist/esm/auth/capability-discovery.js.map +1 -1
  56. package/dist/esm/auth/index.js.map +1 -1
  57. package/dist/esm/auth/interactive-oauth-flow.js.map +1 -1
  58. package/dist/esm/auth/oauth-callback-listener.js.map +1 -1
  59. package/dist/esm/auth/pkce.js.map +1 -1
  60. package/dist/esm/auth/rfc9728-discovery.js.map +1 -1
  61. package/dist/esm/auth/types.js.map +1 -1
  62. package/dist/esm/client-helpers.js.map +1 -1
  63. package/dist/esm/config/server-loader.js.map +1 -1
  64. package/dist/esm/config/validate-config.js.map +1 -1
  65. package/dist/esm/connection/connect-client.js.map +1 -1
  66. package/dist/esm/connection/existing-process-transport.js.map +1 -1
  67. package/dist/esm/connection/types.d.ts +1 -1
  68. package/dist/esm/connection/types.js.map +1 -1
  69. package/dist/esm/connection/wait-for-http-ready.js.map +1 -1
  70. package/dist/esm/constants.js.map +1 -1
  71. package/dist/esm/dcr/dcr-authenticator.js.map +1 -1
  72. package/dist/esm/dcr/dynamic-client-registrar.js.map +1 -1
  73. package/dist/esm/dcr/index.js.map +1 -1
  74. package/dist/esm/index.js.map +1 -1
  75. package/dist/esm/lib/url-utils.js.map +1 -1
  76. package/dist/esm/monkey-patches.js.map +1 -1
  77. package/dist/esm/response-wrappers.js +6 -3
  78. package/dist/esm/response-wrappers.js.map +1 -1
  79. package/dist/esm/search/index.js.map +1 -1
  80. package/dist/esm/search/search.js.map +1 -1
  81. package/dist/esm/search/types.js.map +1 -1
  82. package/dist/esm/spawn/spawn-server.js.map +1 -1
  83. package/dist/esm/spawn/spawn-servers.js.map +1 -1
  84. package/dist/esm/types.js.map +1 -1
  85. package/dist/esm/utils/logger.js.map +1 -1
  86. package/dist/esm/utils/path-utils.js.map +1 -1
  87. package/dist/esm/utils/sanitizer.js.map +1 -1
  88. package/package.json +11 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/dcr/dcr-authenticator.ts"],"sourcesContent":["/**\n * DCR Authenticator\n * Consolidates DCR and OAuth flow logic for MCP HTTP servers\n */\n\nimport path from 'node:path';\nimport * as fs from 'fs';\nimport Keyv from 'keyv';\nimport { KeyvFile } from 'keyv-file';\nimport { InteractiveOAuthFlow } from '../auth/interactive-oauth-flow.ts';\nimport type { AuthCapabilities, TokenSet } from '../auth/types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { DynamicClientRegistrar } from './dynamic-client-registrar.ts';\n\n/**\n * DcrAuthenticator configuration options\n */\nexport interface DcrAuthenticatorOptions {\n /** Custom Keyv store (for testing) - if not provided, uses default ~/.mcpeasy/tokens.json */\n tokenStore?: Keyv;\n /** Headless mode (don't open browser) */\n headless?: boolean;\n /** Required redirect URI for OAuth callback */\n redirectUri: string;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: Logger;\n}\n\n/**\n * Buffer time before token expiry to trigger proactive refresh (5 minutes)\n */\nconst REFRESH_BUFFER_MS = 5 * 60 * 1000;\n\n/**\n * DcrAuthenticator manages authentication for MCP HTTP servers\n * Handles DCR registration, OAuth flows, and token management\n */\nexport class DcrAuthenticator {\n private tokenStore: Keyv;\n private dcrClient: DynamicClientRegistrar;\n private oauthFlow: InteractiveOAuthFlow;\n private headless: boolean;\n private redirectUri: string;\n private logger: Logger;\n\n constructor(options: DcrAuthenticatorOptions) {\n if (options.tokenStore) {\n this.tokenStore = options.tokenStore;\n } else {\n // Default CLI store in .mcp-z directory (per-project)\n const storePath = path.join(process.cwd(), '.mcp-z', 'tokens.json');\n\n // Ensure directory exists before creating store\n fs.mkdirSync(path.dirname(storePath), { recursive: true });\n\n this.tokenStore = new Keyv({\n store: new KeyvFile({ filename: storePath }),\n });\n }\n this.dcrClient = new DynamicClientRegistrar();\n this.oauthFlow = new InteractiveOAuthFlow();\n this.headless = options.headless || false;\n this.redirectUri = options.redirectUri;\n this.logger = options.logger ?? defaultLogger;\n }\n\n /**\n * Detect if server is self-hosted DCR (vs external OAuth provider)\n * Self-hosted servers have their own OAuth endpoints and manage token storage\n */\n private async detectSelfHostedMode(baseUrl: string): Promise<boolean> {\n try {\n // Self-hosted DCR servers typically run their own OAuth server\n // Check if this is a self-hosted instance by testing OAuth metadata\n // For now, assume self-hosted if baseUrl matches common localhost patterns\n // TODO: Implement proper self-hosted detection logic\n return baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n } catch (_error) {\n return false; // Assume external mode if detection fails\n }\n }\n\n /**\n * Ensure server is authenticated, performing DCR and OAuth if needed\n * Proactively refreshes tokens if they're within 5 minutes of expiry\n *\n * @param baseUrl - Base URL of the server (e.g., https://example.com)\n * @param capabilities - Auth capabilities from .well-known endpoint\n * @returns Valid token set ready to use\n *\n * @throws Error if authentication fails\n *\n * @example\n * const authenticator = new DcrAuthenticator({ redirectUri: 'http://localhost:3000/callback' });\n * const tokens = await authenticator.ensureAuthenticated(\n * 'https://example.com',\n * capabilities\n * );\n */\n async ensureAuthenticated(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n // Auto-detect server mode\n const isSelfHosted = await this.detectSelfHostedMode(baseUrl);\n\n if (isSelfHosted) {\n return this.ensureAuthenticatedSelfHosted(baseUrl, capabilities);\n }\n return this.ensureAuthenticatedExternal(baseUrl, capabilities);\n }\n\n /**\n * Handle authentication for self-hosted DCR servers\n * Self-hosted servers manage their own token storage via /oauth/verify\n */\n private async ensureAuthenticatedSelfHosted(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n const dcrTokenKey = `dcr-tokens:${baseUrl}`;\n\n // 1. Check for existing DCR tokens (different from external tokens)\n let tokens = (await this.tokenStore.get(dcrTokenKey)) as TokenSet | undefined;\n\n if (tokens) {\n // 2. Verify token is still valid by calling /oauth/verify\n try {\n const verifyUrl = `${baseUrl}/oauth/verify`;\n const verifyResponse = await fetch(verifyUrl, {\n headers: { Authorization: `Bearer ${tokens.accessToken}`, Connection: 'close' },\n });\n\n if (verifyResponse.ok) {\n const verifyData = (await verifyResponse.json()) as { token?: string };\n if (verifyData.token === tokens.accessToken) {\n // Token is still valid with the self-hosted server\n return tokens;\n }\n }\n } catch (_error) {\n // Token verification failed - need to re-authenticate\n }\n\n // Token is expired or invalid\n await this.tokenStore.delete(dcrTokenKey);\n tokens = undefined;\n }\n\n // 3. No valid tokens - perform full DCR + OAuth flow\n if (!capabilities.registrationEndpoint || !capabilities.authorizationEndpoint || !capabilities.tokenEndpoint) {\n throw new Error('Server does not provide required OAuth endpoints');\n }\n\n this.logger.debug('🔐 No valid tokens found, starting self-hosted DCR authentication...');\n\n // Extract port from pre-resolved redirectUri\n const port = parseInt(new URL(this.redirectUri).port, 10) || (this.redirectUri.startsWith('https:') ? 443 : 80);\n\n // Register OAuth client via DCR\n this.logger.debug('📝 Registering OAuth client with self-hosted server...');\n const client = await this.dcrClient.registerClient(capabilities.registrationEndpoint, {\n redirectUri: this.redirectUri,\n });\n\n // Perform OAuth authorization flow with PKCE (RFC 7636)\n const flowOptions: { port: number; headless: boolean; scopes?: string[]; redirectUri: string; pkce: boolean; logger: Logger } = {\n port,\n headless: this.headless,\n redirectUri: this.redirectUri,\n pkce: true,\n logger: this.logger,\n };\n if (capabilities.scopes) {\n flowOptions.scopes = capabilities.scopes;\n }\n\n tokens = await this.oauthFlow.performAuthFlow(capabilities.authorizationEndpoint, capabilities.tokenEndpoint, client.clientId, client.clientSecret, flowOptions);\n\n // For self-hosted mode, verify the token works with /oauth/verify immediately\n try {\n const verifyUrl = `${baseUrl}/oauth/verify`;\n const verifyResponse = await fetch(verifyUrl, {\n headers: { Authorization: `Bearer ${tokens.accessToken}`, Connection: 'close' },\n });\n\n if (!verifyResponse.ok) {\n throw new Error(`DCR token verification failed after authentication: ${verifyResponse.status}`);\n }\n\n const verifyData = (await verifyResponse.json()) as { token?: string };\n if (verifyData.token !== tokens.accessToken) {\n throw new Error('DCR server returned different token in verification');\n }\n\n this.logger.debug('✅ DCR token verified with self-hosted server');\n } catch (error) {\n this.logger.error('❌ DCR token verification failed:', error instanceof Error ? error.message : String(error));\n throw new Error('Self-hosted DCR authentication completed but token verification failed');\n }\n\n // Save tokens for future use\n await this.tokenStore.set(dcrTokenKey, tokens);\n this.logger.debug('✅ Self-hosted DCR authentication successful, tokens saved');\n\n return tokens;\n }\n\n /**\n * Handle authentication for external OAuth providers (original implementation)\n */\n private async ensureAuthenticatedExternal(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n const tokenKey = `tokens:${baseUrl}`;\n\n // 1. Check for existing tokens\n let tokens = (await this.tokenStore.get(tokenKey)) as TokenSet | undefined;\n\n if (tokens) {\n // 2. Proactive refresh if token expires within 5 minutes\n if (tokens.expiresAt < Date.now() + REFRESH_BUFFER_MS) {\n this.logger.debug('🔄 Refreshing access token...');\n\n try {\n tokens = await this.refreshTokens(tokens, capabilities.tokenEndpoint);\n await this.tokenStore.set(tokenKey, tokens);\n this.logger.debug('✅ Token refreshed successfully');\n } catch (_error) {\n // Refresh failed - clear tokens and re-authenticate\n this.logger.warn('⚠️ Token refresh failed, re-authenticating...');\n await this.tokenStore.delete(tokenKey);\n tokens = undefined;\n }\n }\n\n if (tokens) {\n return tokens;\n }\n }\n\n // 3. No valid tokens - perform DCR + OAuth flow\n if (!capabilities.registrationEndpoint || !capabilities.authorizationEndpoint || !capabilities.tokenEndpoint) {\n throw new Error('Server does not provide required OAuth endpoints');\n }\n\n this.logger.debug('🔐 No valid tokens found, starting external OAuth authentication...');\n\n // Extract port from pre-resolved redirectUri\n const port = parseInt(new URL(this.redirectUri).port, 10) || (this.redirectUri.startsWith('https:') ? 443 : 80);\n\n // Register OAuth client via DCR\n this.logger.debug('📝 Registering OAuth client...');\n const client = await this.dcrClient.registerClient(capabilities.registrationEndpoint, {\n redirectUri: this.redirectUri,\n });\n\n // Perform OAuth authorization flow with PKCE (RFC 7636)\n const flowOptions: { port: number; headless: boolean; scopes?: string[]; redirectUri: string; pkce: boolean; logger: Logger } = {\n port,\n headless: this.headless,\n redirectUri: this.redirectUri,\n pkce: true,\n logger: this.logger,\n };\n if (capabilities.scopes) {\n flowOptions.scopes = capabilities.scopes;\n }\n\n tokens = await this.oauthFlow.performAuthFlow(capabilities.authorizationEndpoint, capabilities.tokenEndpoint, client.clientId, client.clientSecret, flowOptions);\n\n // Save tokens for future use\n await this.tokenStore.set(tokenKey, tokens);\n this.logger.debug('✅ Authentication successful, tokens saved');\n\n return tokens;\n }\n\n /**\n * Refresh access token using refresh token\n */\n private async refreshTokens(tokens: TokenSet, tokenEndpoint?: string): Promise<TokenSet> {\n if (!tokenEndpoint) {\n throw new Error('Token endpoint not available for refresh');\n }\n\n if (!tokens.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n if (!tokens.clientId || !tokens.clientSecret) {\n throw new Error('Client credentials not available for refresh');\n }\n\n return await this.oauthFlow.refreshTokens(tokenEndpoint, tokens.refreshToken, tokens.clientId, tokens.clientSecret);\n }\n\n /**\n * Delete stored tokens for a server\n */\n async deleteTokens(baseUrl: string): Promise<void> {\n const tokenKey = `tokens:${baseUrl}`;\n await this.tokenStore.delete(tokenKey);\n this.logger.debug(`🗑️ Deleted tokens for ${baseUrl}`);\n }\n}\n"],"names":["path","fs","Keyv","KeyvFile","InteractiveOAuthFlow","logger","defaultLogger","DynamicClientRegistrar","REFRESH_BUFFER_MS","DcrAuthenticator","detectSelfHostedMode","baseUrl","includes","_error","ensureAuthenticated","capabilities","isSelfHosted","ensureAuthenticatedSelfHosted","ensureAuthenticatedExternal","dcrTokenKey","tokens","tokenStore","get","verifyUrl","verifyResponse","fetch","headers","Authorization","accessToken","Connection","ok","verifyData","json","token","delete","undefined","registrationEndpoint","authorizationEndpoint","tokenEndpoint","Error","debug","port","parseInt","URL","redirectUri","startsWith","client","dcrClient","registerClient","flowOptions","headless","pkce","scopes","oauthFlow","performAuthFlow","clientId","clientSecret","status","error","message","String","set","tokenKey","expiresAt","Date","now","refreshTokens","warn","refreshToken","deleteTokens","options","storePath","join","process","cwd","mkdirSync","dirname","recursive","store","filename"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/dcr/dcr-authenticator.ts"],"sourcesContent":["/**\n * DCR Authenticator\n * Consolidates DCR and OAuth flow logic for MCP HTTP servers\n */\n\nimport path from 'node:path';\nimport * as fs from 'fs';\nimport Keyv from 'keyv';\nimport { KeyvFile } from 'keyv-file';\nimport { InteractiveOAuthFlow } from '../auth/interactive-oauth-flow.ts';\nimport type { AuthCapabilities, TokenSet } from '../auth/types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { DynamicClientRegistrar } from './dynamic-client-registrar.ts';\n\n/**\n * DcrAuthenticator configuration options\n */\nexport interface DcrAuthenticatorOptions {\n /** Custom Keyv store (for testing) - if not provided, uses default ~/.mcpeasy/tokens.json */\n tokenStore?: Keyv;\n /** Headless mode (don't open browser) */\n headless?: boolean;\n /** Required redirect URI for OAuth callback */\n redirectUri: string;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: Logger;\n}\n\n/**\n * Buffer time before token expiry to trigger proactive refresh (5 minutes)\n */\nconst REFRESH_BUFFER_MS = 5 * 60 * 1000;\n\n/**\n * DcrAuthenticator manages authentication for MCP HTTP servers\n * Handles DCR registration, OAuth flows, and token management\n */\nexport class DcrAuthenticator {\n private tokenStore: Keyv;\n private dcrClient: DynamicClientRegistrar;\n private oauthFlow: InteractiveOAuthFlow;\n private headless: boolean;\n private redirectUri: string;\n private logger: Logger;\n\n constructor(options: DcrAuthenticatorOptions) {\n if (options.tokenStore) {\n this.tokenStore = options.tokenStore;\n } else {\n // Default CLI store in .mcp-z directory (per-project)\n const storePath = path.join(process.cwd(), '.mcp-z', 'tokens.json');\n\n // Ensure directory exists before creating store\n fs.mkdirSync(path.dirname(storePath), { recursive: true });\n\n this.tokenStore = new Keyv({\n store: new KeyvFile({ filename: storePath }),\n });\n }\n this.dcrClient = new DynamicClientRegistrar();\n this.oauthFlow = new InteractiveOAuthFlow();\n this.headless = options.headless || false;\n this.redirectUri = options.redirectUri;\n this.logger = options.logger ?? defaultLogger;\n }\n\n /**\n * Detect if server is self-hosted DCR (vs external OAuth provider)\n * Self-hosted servers have their own OAuth endpoints and manage token storage\n */\n private async detectSelfHostedMode(baseUrl: string): Promise<boolean> {\n try {\n // Self-hosted DCR servers typically run their own OAuth server\n // Check if this is a self-hosted instance by testing OAuth metadata\n // For now, assume self-hosted if baseUrl matches common localhost patterns\n // TODO: Implement proper self-hosted detection logic\n return baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n } catch (_error) {\n return false; // Assume external mode if detection fails\n }\n }\n\n /**\n * Ensure server is authenticated, performing DCR and OAuth if needed\n * Proactively refreshes tokens if they're within 5 minutes of expiry\n *\n * @param baseUrl - Base URL of the server (e.g., https://example.com)\n * @param capabilities - Auth capabilities from .well-known endpoint\n * @returns Valid token set ready to use\n *\n * @throws Error if authentication fails\n *\n * @example\n * const authenticator = new DcrAuthenticator({ redirectUri: 'http://localhost:3000/callback' });\n * const tokens = await authenticator.ensureAuthenticated(\n * 'https://example.com',\n * capabilities\n * );\n */\n async ensureAuthenticated(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n // Auto-detect server mode\n const isSelfHosted = await this.detectSelfHostedMode(baseUrl);\n\n if (isSelfHosted) {\n return this.ensureAuthenticatedSelfHosted(baseUrl, capabilities);\n }\n return this.ensureAuthenticatedExternal(baseUrl, capabilities);\n }\n\n /**\n * Handle authentication for self-hosted DCR servers\n * Self-hosted servers manage their own token storage via /oauth/verify\n */\n private async ensureAuthenticatedSelfHosted(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n const dcrTokenKey = `dcr-tokens:${baseUrl}`;\n\n // 1. Check for existing DCR tokens (different from external tokens)\n let tokens = (await this.tokenStore.get(dcrTokenKey)) as TokenSet | undefined;\n\n if (tokens) {\n // 2. Verify token is still valid by calling /oauth/verify\n try {\n const verifyUrl = `${baseUrl}/oauth/verify`;\n const verifyResponse = await fetch(verifyUrl, {\n headers: { Authorization: `Bearer ${tokens.accessToken}`, Connection: 'close' },\n });\n\n if (verifyResponse.ok) {\n const verifyData = (await verifyResponse.json()) as { token?: string };\n if (verifyData.token === tokens.accessToken) {\n // Token is still valid with the self-hosted server\n return tokens;\n }\n }\n } catch (_error) {\n // Token verification failed - need to re-authenticate\n }\n\n // Token is expired or invalid\n await this.tokenStore.delete(dcrTokenKey);\n tokens = undefined;\n }\n\n // 3. No valid tokens - perform full DCR + OAuth flow\n if (!capabilities.registrationEndpoint || !capabilities.authorizationEndpoint || !capabilities.tokenEndpoint) {\n throw new Error('Server does not provide required OAuth endpoints');\n }\n\n this.logger.debug('🔐 No valid tokens found, starting self-hosted DCR authentication...');\n\n // Extract port from pre-resolved redirectUri\n const port = parseInt(new URL(this.redirectUri).port, 10) || (this.redirectUri.startsWith('https:') ? 443 : 80);\n\n // Register OAuth client via DCR\n this.logger.debug('📝 Registering OAuth client with self-hosted server...');\n const client = await this.dcrClient.registerClient(capabilities.registrationEndpoint, {\n redirectUri: this.redirectUri,\n });\n\n // Perform OAuth authorization flow with PKCE (RFC 7636)\n const flowOptions: { port: number; headless: boolean; scopes?: string[]; redirectUri: string; pkce: boolean; logger: Logger } = {\n port,\n headless: this.headless,\n redirectUri: this.redirectUri,\n pkce: true,\n logger: this.logger,\n };\n if (capabilities.scopes) {\n flowOptions.scopes = capabilities.scopes;\n }\n\n tokens = await this.oauthFlow.performAuthFlow(capabilities.authorizationEndpoint, capabilities.tokenEndpoint, client.clientId, client.clientSecret, flowOptions);\n\n // For self-hosted mode, verify the token works with /oauth/verify immediately\n try {\n const verifyUrl = `${baseUrl}/oauth/verify`;\n const verifyResponse = await fetch(verifyUrl, {\n headers: { Authorization: `Bearer ${tokens.accessToken}`, Connection: 'close' },\n });\n\n if (!verifyResponse.ok) {\n throw new Error(`DCR token verification failed after authentication: ${verifyResponse.status}`);\n }\n\n const verifyData = (await verifyResponse.json()) as { token?: string };\n if (verifyData.token !== tokens.accessToken) {\n throw new Error('DCR server returned different token in verification');\n }\n\n this.logger.debug('✅ DCR token verified with self-hosted server');\n } catch (error) {\n this.logger.error('❌ DCR token verification failed:', error instanceof Error ? error.message : String(error));\n throw new Error('Self-hosted DCR authentication completed but token verification failed');\n }\n\n // Save tokens for future use\n await this.tokenStore.set(dcrTokenKey, tokens);\n this.logger.debug('✅ Self-hosted DCR authentication successful, tokens saved');\n\n return tokens;\n }\n\n /**\n * Handle authentication for external OAuth providers (original implementation)\n */\n private async ensureAuthenticatedExternal(baseUrl: string, capabilities: AuthCapabilities): Promise<TokenSet> {\n const tokenKey = `tokens:${baseUrl}`;\n\n // 1. Check for existing tokens\n let tokens = (await this.tokenStore.get(tokenKey)) as TokenSet | undefined;\n\n if (tokens) {\n // 2. Proactive refresh if token expires within 5 minutes\n if (tokens.expiresAt < Date.now() + REFRESH_BUFFER_MS) {\n this.logger.debug('🔄 Refreshing access token...');\n\n try {\n tokens = await this.refreshTokens(tokens, capabilities.tokenEndpoint);\n await this.tokenStore.set(tokenKey, tokens);\n this.logger.debug('✅ Token refreshed successfully');\n } catch (_error) {\n // Refresh failed - clear tokens and re-authenticate\n this.logger.warn('⚠️ Token refresh failed, re-authenticating...');\n await this.tokenStore.delete(tokenKey);\n tokens = undefined;\n }\n }\n\n if (tokens) {\n return tokens;\n }\n }\n\n // 3. No valid tokens - perform DCR + OAuth flow\n if (!capabilities.registrationEndpoint || !capabilities.authorizationEndpoint || !capabilities.tokenEndpoint) {\n throw new Error('Server does not provide required OAuth endpoints');\n }\n\n this.logger.debug('🔐 No valid tokens found, starting external OAuth authentication...');\n\n // Extract port from pre-resolved redirectUri\n const port = parseInt(new URL(this.redirectUri).port, 10) || (this.redirectUri.startsWith('https:') ? 443 : 80);\n\n // Register OAuth client via DCR\n this.logger.debug('📝 Registering OAuth client...');\n const client = await this.dcrClient.registerClient(capabilities.registrationEndpoint, {\n redirectUri: this.redirectUri,\n });\n\n // Perform OAuth authorization flow with PKCE (RFC 7636)\n const flowOptions: { port: number; headless: boolean; scopes?: string[]; redirectUri: string; pkce: boolean; logger: Logger } = {\n port,\n headless: this.headless,\n redirectUri: this.redirectUri,\n pkce: true,\n logger: this.logger,\n };\n if (capabilities.scopes) {\n flowOptions.scopes = capabilities.scopes;\n }\n\n tokens = await this.oauthFlow.performAuthFlow(capabilities.authorizationEndpoint, capabilities.tokenEndpoint, client.clientId, client.clientSecret, flowOptions);\n\n // Save tokens for future use\n await this.tokenStore.set(tokenKey, tokens);\n this.logger.debug('✅ Authentication successful, tokens saved');\n\n return tokens;\n }\n\n /**\n * Refresh access token using refresh token\n */\n private async refreshTokens(tokens: TokenSet, tokenEndpoint?: string): Promise<TokenSet> {\n if (!tokenEndpoint) {\n throw new Error('Token endpoint not available for refresh');\n }\n\n if (!tokens.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n if (!tokens.clientId || !tokens.clientSecret) {\n throw new Error('Client credentials not available for refresh');\n }\n\n return await this.oauthFlow.refreshTokens(tokenEndpoint, tokens.refreshToken, tokens.clientId, tokens.clientSecret);\n }\n\n /**\n * Delete stored tokens for a server\n */\n async deleteTokens(baseUrl: string): Promise<void> {\n const tokenKey = `tokens:${baseUrl}`;\n await this.tokenStore.delete(tokenKey);\n this.logger.debug(`🗑️ Deleted tokens for ${baseUrl}`);\n }\n}\n"],"names":["path","fs","Keyv","KeyvFile","InteractiveOAuthFlow","logger","defaultLogger","DynamicClientRegistrar","REFRESH_BUFFER_MS","DcrAuthenticator","detectSelfHostedMode","baseUrl","includes","_error","ensureAuthenticated","capabilities","isSelfHosted","ensureAuthenticatedSelfHosted","ensureAuthenticatedExternal","dcrTokenKey","tokens","tokenStore","get","verifyUrl","verifyResponse","fetch","headers","Authorization","accessToken","Connection","ok","verifyData","json","token","delete","undefined","registrationEndpoint","authorizationEndpoint","tokenEndpoint","Error","debug","port","parseInt","URL","redirectUri","startsWith","client","dcrClient","registerClient","flowOptions","headless","pkce","scopes","oauthFlow","performAuthFlow","clientId","clientSecret","status","error","message","String","set","tokenKey","expiresAt","Date","now","refreshTokens","warn","refreshToken","deleteTokens","options","storePath","join","process","cwd","mkdirSync","dirname","recursive","store","filename"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/dcr/dynamic-client-registrar.ts"],"sourcesContent":["/**\n * Dynamic Client Registration (DCR) Client\n * Implements RFC 7591 for OAuth client registration\n */\n\nimport type { ClientCredentials, DcrRegistrationOptions } from '../auth/types.ts';\n\n/**\n * DCR Registration Request (RFC 7591)\n */\ninterface DcrRegistrationRequest {\n client_name?: string;\n redirect_uris?: string[];\n grant_types?: string[];\n response_types?: string[];\n token_endpoint_auth_method?: string;\n}\n\n/**\n * DCR Registration Response (RFC 7591)\n */\ninterface DcrRegistrationResponse {\n client_id: string;\n client_secret?: string;\n client_id_issued_at?: number;\n client_secret_expires_at?: number;\n}\n\n/**\n * DynamicClientRegistrar handles Dynamic Client Registration with OAuth servers\n */\nexport class DynamicClientRegistrar {\n /**\n * Register a new OAuth client with the authorization server\n *\n * @param registrationEndpoint - DCR registration endpoint URL\n * @param options - Registration options (client name, redirect URI)\n * @returns Client credentials (client ID and secret)\n *\n * @throws Error if registration fails or server returns error\n *\n * @example\n * const registrar = new DynamicClientRegistrar();\n * const creds = await registrar.registerClient(\n * 'https://example.com/oauth/register',\n * { clientName: '@mcp-z/client', redirectUri: 'http://localhost:3000/callback' }\n * );\n * console.log('Client ID:', creds.clientId);\n */\n async registerClient(registrationEndpoint: string, options: DcrRegistrationOptions = {}): Promise<ClientCredentials> {\n const requestBody: DcrRegistrationRequest = {\n client_name: options.clientName || '@mcp-z/client',\n redirect_uris: options.redirectUri ? [options.redirectUri] : ['http://localhost:3000/callback'],\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method: 'client_secret_basic',\n };\n\n const response = await fetch(registrationEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`DCR registration failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as DcrRegistrationResponse;\n\n if (!data.client_id) {\n throw new Error('DCR registration response missing client_id');\n }\n\n const credentials: ClientCredentials = {\n clientId: data.client_id,\n clientSecret: data.client_secret || '',\n };\n\n if (data.client_id_issued_at) {\n credentials.issuedAt = data.client_id_issued_at;\n }\n\n return credentials;\n }\n}\n"],"names":["DynamicClientRegistrar","registerClient","registrationEndpoint","options","requestBody","client_name","clientName","redirect_uris","redirectUri","grant_types","response_types","token_endpoint_auth_method","response","fetch","method","headers","Accept","Connection","body","JSON","stringify","ok","errorText","text","Error","status","data","json","client_id","credentials","clientId","clientSecret","client_secret","client_id_issued_at","issuedAt"],"mappings":"AAAA;;;CAGC,GAyBD;;CAEC,GACD,OAAO,MAAMA;IACX;;;;;;;;;;;;;;;;GAgBC,GACD,MAAMC,eAAeC,oBAA4B,EAAEC,UAAkC,CAAC,CAAC,EAA8B;QACnH,MAAMC,cAAsC;YAC1CC,aAAaF,QAAQG,UAAU,IAAI;YACnCC,eAAeJ,QAAQK,WAAW,GAAG;gBAACL,QAAQK,WAAW;aAAC,GAAG;gBAAC;aAAiC;YAC/FC,aAAa;gBAAC;gBAAsB;aAAgB;YACpDC,gBAAgB;gBAAC;aAAO;YACxBC,4BAA4B;QAC9B;QAEA,MAAMC,WAAW,MAAMC,MAAMX,sBAAsB;YACjDY,QAAQ;YACRC,SAAS;gBACP,gBAAgB;gBAChBC,QAAQ;gBACRC,YAAY;YACd;YACAC,MAAMC,KAAKC,SAAS,CAAChB;QACvB;QAEA,IAAI,CAACQ,SAASS,EAAE,EAAE;YAChB,MAAMC,YAAY,MAAMV,SAASW,IAAI;YACrC,MAAM,IAAIC,MAAM,CAAC,yBAAyB,EAAEZ,SAASa,MAAM,CAAC,GAAG,EAAEH,WAAW;QAC9E;QAEA,MAAMI,OAAQ,MAAMd,SAASe,IAAI;QAEjC,IAAI,CAACD,KAAKE,SAAS,EAAE;YACnB,MAAM,IAAIJ,MAAM;QAClB;QAEA,MAAMK,cAAiC;YACrCC,UAAUJ,KAAKE,SAAS;YACxBG,cAAcL,KAAKM,aAAa,IAAI;QACtC;QAEA,IAAIN,KAAKO,mBAAmB,EAAE;YAC5BJ,YAAYK,QAAQ,GAAGR,KAAKO,mBAAmB;QACjD;QAEA,OAAOJ;IACT;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/dcr/dynamic-client-registrar.ts"],"sourcesContent":["/**\n * Dynamic Client Registration (DCR) Client\n * Implements RFC 7591 for OAuth client registration\n */\n\nimport type { ClientCredentials, DcrRegistrationOptions } from '../auth/types.ts';\n\n/**\n * DCR Registration Request (RFC 7591)\n */\ninterface DcrRegistrationRequest {\n client_name?: string;\n redirect_uris?: string[];\n grant_types?: string[];\n response_types?: string[];\n token_endpoint_auth_method?: string;\n}\n\n/**\n * DCR Registration Response (RFC 7591)\n */\ninterface DcrRegistrationResponse {\n client_id: string;\n client_secret?: string;\n client_id_issued_at?: number;\n client_secret_expires_at?: number;\n}\n\n/**\n * DynamicClientRegistrar handles Dynamic Client Registration with OAuth servers\n */\nexport class DynamicClientRegistrar {\n /**\n * Register a new OAuth client with the authorization server\n *\n * @param registrationEndpoint - DCR registration endpoint URL\n * @param options - Registration options (client name, redirect URI)\n * @returns Client credentials (client ID and secret)\n *\n * @throws Error if registration fails or server returns error\n *\n * @example\n * const registrar = new DynamicClientRegistrar();\n * const creds = await registrar.registerClient(\n * 'https://example.com/oauth/register',\n * { clientName: '@mcp-z/client', redirectUri: 'http://localhost:3000/callback' }\n * );\n * console.log('Client ID:', creds.clientId);\n */\n async registerClient(registrationEndpoint: string, options: DcrRegistrationOptions = {}): Promise<ClientCredentials> {\n const requestBody: DcrRegistrationRequest = {\n client_name: options.clientName || '@mcp-z/client',\n redirect_uris: options.redirectUri ? [options.redirectUri] : ['http://localhost:3000/callback'],\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method: 'client_secret_basic',\n };\n\n const response = await fetch(registrationEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`DCR registration failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as DcrRegistrationResponse;\n\n if (!data.client_id) {\n throw new Error('DCR registration response missing client_id');\n }\n\n const credentials: ClientCredentials = {\n clientId: data.client_id,\n clientSecret: data.client_secret || '',\n };\n\n if (data.client_id_issued_at) {\n credentials.issuedAt = data.client_id_issued_at;\n }\n\n return credentials;\n }\n}\n"],"names":["DynamicClientRegistrar","registerClient","registrationEndpoint","options","requestBody","client_name","clientName","redirect_uris","redirectUri","grant_types","response_types","token_endpoint_auth_method","response","fetch","method","headers","Accept","Connection","body","JSON","stringify","ok","errorText","text","Error","status","data","json","client_id","credentials","clientId","clientSecret","client_secret","client_id_issued_at","issuedAt"],"mappings":"AAAA;;;CAGC,GAyBD;;CAEC,GACD,OAAO,MAAMA;IACX;;;;;;;;;;;;;;;;GAgBC,GACD,MAAMC,eAAeC,oBAA4B,EAAEC,UAAkC,CAAC,CAAC,EAA8B;QACnH,MAAMC,cAAsC;YAC1CC,aAAaF,QAAQG,UAAU,IAAI;YACnCC,eAAeJ,QAAQK,WAAW,GAAG;gBAACL,QAAQK,WAAW;aAAC,GAAG;gBAAC;aAAiC;YAC/FC,aAAa;gBAAC;gBAAsB;aAAgB;YACpDC,gBAAgB;gBAAC;aAAO;YACxBC,4BAA4B;QAC9B;QAEA,MAAMC,WAAW,MAAMC,MAAMX,sBAAsB;YACjDY,QAAQ;YACRC,SAAS;gBACP,gBAAgB;gBAChBC,QAAQ;gBACRC,YAAY;YACd;YACAC,MAAMC,KAAKC,SAAS,CAAChB;QACvB;QAEA,IAAI,CAACQ,SAASS,EAAE,EAAE;YAChB,MAAMC,YAAY,MAAMV,SAASW,IAAI;YACrC,MAAM,IAAIC,MAAM,CAAC,yBAAyB,EAAEZ,SAASa,MAAM,CAAC,GAAG,EAAEH,WAAW;QAC9E;QAEA,MAAMI,OAAQ,MAAMd,SAASe,IAAI;QAEjC,IAAI,CAACD,KAAKE,SAAS,EAAE;YACnB,MAAM,IAAIJ,MAAM;QAClB;QAEA,MAAMK,cAAiC;YACrCC,UAAUJ,KAAKE,SAAS;YACxBG,cAAcL,KAAKM,aAAa,IAAI;QACtC;QAEA,IAAIN,KAAKO,mBAAmB,EAAE;YAC5BJ,YAAYK,QAAQ,GAAGR,KAAKO,mBAAmB;QACjD;QAEA,OAAOJ;IACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/dcr/index.ts"],"sourcesContent":["/**\n * DCR (Dynamic Client Registration) Module\n * Exports public API for DCR authentication\n */\n\nexport type { ClientCredentials, DcrRegistrationOptions } from '../auth/types.ts';\nexport type { DcrAuthenticatorOptions } from './dcr-authenticator.ts';\nexport { DcrAuthenticator } from './dcr-authenticator.ts';\nexport { DynamicClientRegistrar } from './dynamic-client-registrar.ts';\n"],"names":["DcrAuthenticator","DynamicClientRegistrar"],"mappings":"AAAA;;;CAGC,GAID,SAASA,gBAAgB,QAAQ,yBAAyB;AAC1D,SAASC,sBAAsB,QAAQ,gCAAgC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/dcr/index.ts"],"sourcesContent":["/**\n * DCR (Dynamic Client Registration) Module\n * Exports public API for DCR authentication\n */\n\nexport type { ClientCredentials, DcrRegistrationOptions } from '../auth/types.ts';\nexport type { DcrAuthenticatorOptions } from './dcr-authenticator.ts';\nexport { DcrAuthenticator } from './dcr-authenticator.ts';\nexport { DynamicClientRegistrar } from './dynamic-client-registrar.ts';\n"],"names":["DcrAuthenticator","DynamicClientRegistrar"],"mappings":"AAAA;;;CAGC,GAID,SAASA,gBAAgB,QAAQ,yBAAyB;AAC1D,SAASC,sBAAsB,QAAQ,gCAAgC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/index.ts"],"sourcesContent":["/**\n * @mcp-z/client - MCP Client Library\n */\n\n// Config types (from schema)\nexport type { McpServerEntry, StartConfig } from '../schemas/servers.d.ts';\n// Auth - OAuth utilities\nexport { probeAuthCapabilities } from './auth/capability-discovery.ts';\nexport type { AuthCapabilities, CallbackResult, OAuthCallbackListenerOptions, OAuthFlowOptions, TokenSet } from './auth/index.ts';\nexport { InteractiveOAuthFlow } from './auth/interactive-oauth-flow.ts';\nexport { OAuthCallbackListener } from './auth/oauth-callback-listener.ts';\n// Client helpers and lightweight overloads\nexport { decorateClient, type ManagedClient, type PromptArguments, type WrappedCallToolReturn, type WrappedGetPromptReturn, type WrappedReadResourceReturn } from './client-helpers.ts';\n// Config - Configuration validation\nexport { type ValidationResult, validateServers } from './config/validate-config.ts';\n// Connection - MCP client connection utilities (internal helpers exposed for advanced use)\nexport type { JsonValue, PromptArgument, ToolArguments } from './connection/types.ts';\n// DCR - Dynamic Client Registration utilities\nexport { DcrAuthenticator } from './dcr/dcr-authenticator.ts';\nexport { DynamicClientRegistrar } from './dcr/dynamic-client-registrar.ts';\nexport type { ClientCredentials, DcrAuthenticatorOptions, DcrRegistrationOptions } from './dcr/index.ts';\nexport {\n type JsonValidator,\n type NativeCallToolResponse,\n type NativeGetPromptResponse,\n type NativeReadResourceResponse,\n PromptResponseError,\n PromptResponseWrapper,\n ResourceResponseError,\n ResourceResponseWrapper,\n ToolResponseError,\n ToolResponseWrapper,\n} from './response-wrappers.ts';\nexport type { CapabilityClient, CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './search/index.ts';\n// Search - Capability discovery\nexport { buildCapabilityIndex, search, searchCapabilities } from './search/index.ts';\n// Spawn - Server registry (v3 API)\nexport { type CloseResult, type CreateServerRegistryOptions, createServerRegistry, type Dialect, type ServerRegistry, type ServersConfig } from './spawn/spawn-servers.ts';\nexport type { TransportType } from './types.ts';\n// Utils - Shared utilities\nexport { getLogLevel, type Logger, type LogLevel, logger, setLogLevel } from './utils/logger.ts';\nexport { resolveArgsPaths, resolvePath } from './utils/path-utils.ts';\n"],"names":["probeAuthCapabilities","InteractiveOAuthFlow","OAuthCallbackListener","decorateClient","validateServers","DcrAuthenticator","DynamicClientRegistrar","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","search","searchCapabilities","createServerRegistry","getLogLevel","logger","setLogLevel","resolveArgsPaths","resolvePath"],"mappings":"AAAA;;CAEC,GAED,6BAA6B;AAE7B,yBAAyB;AACzB,SAASA,qBAAqB,QAAQ,iCAAiC;AAEvE,SAASC,oBAAoB,QAAQ,mCAAmC;AACxE,SAASC,qBAAqB,QAAQ,oCAAoC;AAC1E,2CAA2C;AAC3C,SAASC,cAAc,QAA2I,sBAAsB;AACxL,oCAAoC;AACpC,SAAgCC,eAAe,QAAQ,8BAA8B;AAGrF,8CAA8C;AAC9C,SAASC,gBAAgB,QAAQ,6BAA6B;AAC9D,SAASC,sBAAsB,QAAQ,oCAAoC;AAE3E,SAKEC,mBAAmB,EACnBC,qBAAqB,EACrBC,qBAAqB,EACrBC,uBAAuB,EACvBC,iBAAiB,EACjBC,mBAAmB,QACd,yBAAyB;AAEhC,gCAAgC;AAChC,SAASC,oBAAoB,EAAEC,MAAM,EAAEC,kBAAkB,QAAQ,oBAAoB;AACrF,mCAAmC;AACnC,SAA6DC,oBAAoB,QAA+D,2BAA2B;AAE3K,2BAA2B;AAC3B,SAASC,WAAW,EAA8BC,MAAM,EAAEC,WAAW,QAAQ,oBAAoB;AACjG,SAASC,gBAAgB,EAAEC,WAAW,QAAQ,wBAAwB"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/index.ts"],"sourcesContent":["/**\n * @mcp-z/client - MCP Client Library\n */\n\n// Config types (from schema)\nexport type { McpServerEntry, StartConfig } from '../schemas/servers.d.ts';\n// Auth - OAuth utilities\nexport { probeAuthCapabilities } from './auth/capability-discovery.ts';\nexport type { AuthCapabilities, CallbackResult, OAuthCallbackListenerOptions, OAuthFlowOptions, TokenSet } from './auth/index.ts';\nexport { InteractiveOAuthFlow } from './auth/interactive-oauth-flow.ts';\nexport { OAuthCallbackListener } from './auth/oauth-callback-listener.ts';\n// Client helpers and lightweight overloads\nexport { decorateClient, type ManagedClient, type PromptArguments, type WrappedCallToolReturn, type WrappedGetPromptReturn, type WrappedReadResourceReturn } from './client-helpers.ts';\n// Config - Configuration validation\nexport { type ValidationResult, validateServers } from './config/validate-config.ts';\n// Connection - MCP client connection utilities (internal helpers exposed for advanced use)\nexport type { JsonValue, PromptArgument, ToolArguments } from './connection/types.ts';\n// DCR - Dynamic Client Registration utilities\nexport { DcrAuthenticator } from './dcr/dcr-authenticator.ts';\nexport { DynamicClientRegistrar } from './dcr/dynamic-client-registrar.ts';\nexport type { ClientCredentials, DcrAuthenticatorOptions, DcrRegistrationOptions } from './dcr/index.ts';\nexport {\n type JsonValidator,\n type NativeCallToolResponse,\n type NativeGetPromptResponse,\n type NativeReadResourceResponse,\n PromptResponseError,\n PromptResponseWrapper,\n ResourceResponseError,\n ResourceResponseWrapper,\n ToolResponseError,\n ToolResponseWrapper,\n} from './response-wrappers.ts';\nexport type { CapabilityClient, CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './search/index.ts';\n// Search - Capability discovery\nexport { buildCapabilityIndex, search, searchCapabilities } from './search/index.ts';\n// Spawn - Server registry (v3 API)\nexport { type CloseResult, type CreateServerRegistryOptions, createServerRegistry, type Dialect, type ServerRegistry, type ServersConfig } from './spawn/spawn-servers.ts';\nexport type { TransportType } from './types.ts';\n// Utils - Shared utilities\nexport { getLogLevel, type Logger, type LogLevel, logger, setLogLevel } from './utils/logger.ts';\nexport { resolveArgsPaths, resolvePath } from './utils/path-utils.ts';\n"],"names":["probeAuthCapabilities","InteractiveOAuthFlow","OAuthCallbackListener","decorateClient","validateServers","DcrAuthenticator","DynamicClientRegistrar","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","search","searchCapabilities","createServerRegistry","getLogLevel","logger","setLogLevel","resolveArgsPaths","resolvePath"],"mappings":"AAAA;;CAEC,GAED,6BAA6B;AAE7B,yBAAyB;AACzB,SAASA,qBAAqB,QAAQ,iCAAiC;AAEvE,SAASC,oBAAoB,QAAQ,mCAAmC;AACxE,SAASC,qBAAqB,QAAQ,oCAAoC;AAC1E,2CAA2C;AAC3C,SAASC,cAAc,QAA2I,sBAAsB;AACxL,oCAAoC;AACpC,SAAgCC,eAAe,QAAQ,8BAA8B;AAGrF,8CAA8C;AAC9C,SAASC,gBAAgB,QAAQ,6BAA6B;AAC9D,SAASC,sBAAsB,QAAQ,oCAAoC;AAE3E,SAKEC,mBAAmB,EACnBC,qBAAqB,EACrBC,qBAAqB,EACrBC,uBAAuB,EACvBC,iBAAiB,EACjBC,mBAAmB,QACd,yBAAyB;AAEhC,gCAAgC;AAChC,SAASC,oBAAoB,EAAEC,MAAM,EAAEC,kBAAkB,QAAQ,oBAAoB;AACrF,mCAAmC;AACnC,SAA6DC,oBAAoB,QAA+D,2BAA2B;AAE3K,2BAA2B;AAC3B,SAASC,WAAW,EAA8BC,MAAM,EAAEC,WAAW,QAAQ,oBAAoB;AACjG,SAASC,gBAAgB,EAAEC,WAAW,QAAQ,wBAAwB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/lib/url-utils.ts"],"sourcesContent":["export function normalizeUrl(input: string): string {\n try {\n const url = new URL(input);\n url.search = '';\n url.hash = '';\n url.pathname = url.pathname.replace(/\\/+$/, '');\n return url.origin + url.pathname;\n } catch {\n return input.replace(/\\/+$/, '');\n }\n}\n\nexport function joinWellKnown(baseUrl: string, suffix: string): string {\n return `${normalizeUrl(baseUrl)}${suffix}`;\n}\n"],"names":["normalizeUrl","input","url","URL","search","hash","pathname","replace","origin","joinWellKnown","baseUrl","suffix"],"mappings":"AAAA,OAAO,SAASA,aAAaC,KAAa;IACxC,IAAI;QACF,MAAMC,MAAM,IAAIC,IAAIF;QACpBC,IAAIE,MAAM,GAAG;QACbF,IAAIG,IAAI,GAAG;QACXH,IAAII,QAAQ,GAAGJ,IAAII,QAAQ,CAACC,OAAO,CAAC,QAAQ;QAC5C,OAAOL,IAAIM,MAAM,GAAGN,IAAII,QAAQ;IAClC,EAAE,OAAM;QACN,OAAOL,MAAMM,OAAO,CAAC,QAAQ;IAC/B;AACF;AAEA,OAAO,SAASE,cAAcC,OAAe,EAAEC,MAAc;IAC3D,OAAO,GAAGX,aAAaU,WAAWC,QAAQ;AAC5C"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/lib/url-utils.ts"],"sourcesContent":["export function normalizeUrl(input: string): string {\n try {\n const url = new URL(input);\n url.search = '';\n url.hash = '';\n url.pathname = url.pathname.replace(/\\/+$/, '');\n return url.origin + url.pathname;\n } catch {\n return input.replace(/\\/+$/, '');\n }\n}\n\nexport function joinWellKnown(baseUrl: string, suffix: string): string {\n return `${normalizeUrl(baseUrl)}${suffix}`;\n}\n"],"names":["normalizeUrl","input","url","URL","search","hash","pathname","replace","origin","joinWellKnown","baseUrl","suffix"],"mappings":"AAAA,OAAO,SAASA,aAAaC,KAAa;IACxC,IAAI;QACF,MAAMC,MAAM,IAAIC,IAAIF;QACpBC,IAAIE,MAAM,GAAG;QACbF,IAAIG,IAAI,GAAG;QACXH,IAAII,QAAQ,GAAGJ,IAAII,QAAQ,CAACC,OAAO,CAAC,QAAQ;QAC5C,OAAOL,IAAIM,MAAM,GAAGN,IAAII,QAAQ;IAClC,EAAE,OAAM;QACN,OAAOL,MAAMM,OAAO,CAAC,QAAQ;IAC/B;AACF;AAEA,OAAO,SAASE,cAAcC,OAAe,EAAEC,MAAc;IAC3D,OAAO,GAAGX,aAAaU,WAAWC,QAAQ;AAC5C"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/monkey-patches.ts"],"sourcesContent":["/**\n * Monkey patches for MCP SDK bugs\n *\n * These patches fix bugs in dependencies that haven't been fixed upstream yet.\n */\n\nimport { Protocol } from '@modelcontextprotocol/sdk/shared/protocol.js';\n\n/**\n * FIX: Protocol.close() doesn't clear pending timeouts\n *\n * BUG: The MCP SDK's Protocol.close() only closes the transport but does NOT\n * clear pending timeouts from the internal _timeoutInfo Map. This causes Node.js\n * to hang until timeouts fire (default 60 seconds).\n *\n * PATCH: Wrap Protocol.close() to clear all pending timeouts before closing.\n *\n * TO TEST IF STILL NEEDED:\n * 1. Comment out this patch\n * 2. Run: npm run test:unit\n * 3. If tests hang ~60 seconds after completing, bug still exists\n * 4. If tests exit promptly, SDK is fixed and this can be removed\n *\n * UPSTREAM: https://github.com/modelcontextprotocol/typescript-sdk/issues/XXX\n */\nconst originalClose = Protocol.prototype.close;\nProtocol.prototype.close = async function () {\n const self = this as unknown as { _timeoutInfo?: Map<unknown, { timeoutId: ReturnType<typeof setTimeout> }> };\n if (self._timeoutInfo) {\n for (const [, info] of self._timeoutInfo) {\n clearTimeout(info.timeoutId);\n }\n self._timeoutInfo.clear();\n }\n return originalClose.call(this);\n};\n"],"names":["Protocol","originalClose","prototype","close","self","_timeoutInfo","info","clearTimeout","timeoutId","clear","call"],"mappings":"AAAA;;;;CAIC,GAED,SAASA,QAAQ,QAAQ,+CAA+C;AAExE;;;;;;;;;;;;;;;;CAgBC,GACD,MAAMC,gBAAgBD,SAASE,SAAS,CAACC,KAAK;AAC9CH,SAASE,SAAS,CAACC,KAAK,GAAG;IACzB,MAAMC,OAAO,IAAI;IACjB,IAAIA,KAAKC,YAAY,EAAE;QACrB,KAAK,MAAM,GAAGC,KAAK,IAAIF,KAAKC,YAAY,CAAE;YACxCE,aAAaD,KAAKE,SAAS;QAC7B;QACAJ,KAAKC,YAAY,CAACI,KAAK;IACzB;IACA,OAAOR,cAAcS,IAAI,CAAC,IAAI;AAChC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/monkey-patches.ts"],"sourcesContent":["/**\n * Monkey patches for MCP SDK bugs\n *\n * These patches fix bugs in dependencies that haven't been fixed upstream yet.\n */\n\nimport { Protocol } from '@modelcontextprotocol/sdk/shared/protocol.js';\n\n/**\n * FIX: Protocol.close() doesn't clear pending timeouts\n *\n * BUG: The MCP SDK's Protocol.close() only closes the transport but does NOT\n * clear pending timeouts from the internal _timeoutInfo Map. This causes Node.js\n * to hang until timeouts fire (default 60 seconds).\n *\n * PATCH: Wrap Protocol.close() to clear all pending timeouts before closing.\n *\n * TO TEST IF STILL NEEDED:\n * 1. Comment out this patch\n * 2. Run: npm run test:unit\n * 3. If tests hang ~60 seconds after completing, bug still exists\n * 4. If tests exit promptly, SDK is fixed and this can be removed\n *\n * UPSTREAM: https://github.com/modelcontextprotocol/typescript-sdk/issues/XXX\n */\nconst originalClose = Protocol.prototype.close;\nProtocol.prototype.close = async function () {\n const self = this as unknown as { _timeoutInfo?: Map<unknown, { timeoutId: ReturnType<typeof setTimeout> }> };\n if (self._timeoutInfo) {\n for (const [, info] of self._timeoutInfo) {\n clearTimeout(info.timeoutId);\n }\n self._timeoutInfo.clear();\n }\n return originalClose.call(this);\n};\n"],"names":["Protocol","originalClose","prototype","close","self","_timeoutInfo","info","clearTimeout","timeoutId","clear","call"],"mappings":"AAAA;;;;CAIC,GAED,SAASA,QAAQ,QAAQ,+CAA+C;AAExE;;;;;;;;;;;;;;;;CAgBC,GACD,MAAMC,gBAAgBD,SAASE,SAAS,CAACC,KAAK;AAC9CH,SAASE,SAAS,CAACC,KAAK,GAAG;IACzB,MAAMC,OAAO,IAAI;IACjB,IAAIA,KAAKC,YAAY,EAAE;QACrB,KAAK,MAAM,GAAGC,KAAK,IAAIF,KAAKC,YAAY,CAAE;YACxCE,aAAaD,KAAKE,SAAS;QAC7B;QACAJ,KAAKC,YAAY,CAACI,KAAK;IACzB;IACA,OAAOR,cAAcS,IAAI,CAAC,IAAI;AAChC"}
@@ -13,7 +13,8 @@ export class ToolResponseWrapper {
13
13
  json(validator) {
14
14
  const value = this.resolveJsonPayload();
15
15
  if (validator) {
16
- validator(value);
16
+ const assertValid = validator;
17
+ assertValid(value);
17
18
  }
18
19
  return value;
19
20
  }
@@ -94,7 +95,8 @@ export class PromptResponseWrapper {
94
95
  try {
95
96
  const parsed = JSON.parse(textValue);
96
97
  if (validator) {
97
- validator(parsed);
98
+ const assertValid = validator;
99
+ assertValid(parsed);
98
100
  }
99
101
  return parsed;
100
102
  } catch (error) {
@@ -137,7 +139,8 @@ export class ResourceResponseWrapper {
137
139
  try {
138
140
  const parsed = JSON.parse(textValue);
139
141
  if (validator) {
140
- validator(parsed);
142
+ const assertValid = validator;
143
+ assertValid(parsed);
141
144
  }
142
145
  return parsed;
143
146
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/response-wrappers.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { ContentBlock, PromptMessage, TextContent } from '@modelcontextprotocol/sdk/types.js';\n\nexport type NativeCallToolResponse = Awaited<ReturnType<Client['callTool']>>;\nexport type NativeGetPromptResponse = Awaited<ReturnType<Client['getPrompt']>>;\nexport type NativeReadResourceResponse = Awaited<ReturnType<Client['readResource']>>;\n\nexport type JsonValidator<T> = (value: unknown) => asserts value is T;\n\nexport class ToolResponseError extends Error {\n readonly response: NativeCallToolResponse;\n\n constructor(message: string, response: NativeCallToolResponse) {\n super(message);\n this.name = 'ToolResponseError';\n this.response = response;\n }\n}\n\nexport class ToolResponseWrapper {\n private readonly payload: NativeCallToolResponse;\n\n constructor(payload: NativeCallToolResponse) {\n this.payload = payload;\n }\n\n raw(): NativeCallToolResponse {\n return this.payload;\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const value = this.resolveJsonPayload();\n if (validator) {\n validator(value);\n }\n return value as T;\n }\n\n text(): string {\n if (isCompatibilityResult(this.payload)) {\n if (typeof this.payload.toolResult === 'string') {\n return this.payload.toolResult;\n }\n throw new ToolResponseError('Compatibility tool result is not text', this.payload);\n }\n\n this.throwIfError();\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include text content', this.payload);\n }\n\n return textBlock.text;\n }\n\n private resolveJsonPayload(): unknown {\n if (isCompatibilityResult(this.payload)) {\n return this.payload.toolResult;\n }\n\n this.throwIfError();\n\n if (hasStructuredContent(this.payload)) {\n return this.payload.structuredContent;\n }\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include structuredContent or text content', this.payload);\n }\n\n try {\n return JSON.parse(textBlock.text) as unknown;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ToolResponseError(`Failed to parse tool text content as JSON: ${reason}`, this.payload);\n }\n }\n\n private throwIfError(): void {\n if ('isError' in this.payload && this.payload.isError) {\n let detail = typeof this.payload.error === 'object' && this.payload.error && 'message' in this.payload.error ? String((this.payload.error as { message?: unknown }).message ?? '') : '';\n if (!detail) {\n const textBlock = findFirstTextBlock((this.payload.content ?? []) as ContentBlock[]);\n if (textBlock?.text) {\n detail = textBlock.text;\n }\n }\n const message = detail ? `Tool invocation returned an error result: ${detail}` : 'Tool invocation returned an error result';\n throw new ToolResponseError(message, this.payload);\n }\n }\n}\n\nexport class PromptResponseError extends Error {\n readonly response: NativeGetPromptResponse;\n\n constructor(message: string, response: NativeGetPromptResponse) {\n super(message);\n this.name = 'PromptResponseError';\n this.response = response;\n }\n}\n\nexport class PromptResponseWrapper {\n private readonly payload: NativeGetPromptResponse;\n\n constructor(payload: NativeGetPromptResponse) {\n this.payload = payload;\n }\n\n raw(): NativeGetPromptResponse {\n return this.payload;\n }\n\n text(): string {\n const segments = collectPromptText(this.payload.messages);\n if (!segments.length) {\n throw new PromptResponseError('Prompt response did not include text content', this.payload);\n }\n return segments.join('\\n\\n');\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n validator(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new PromptResponseError(`Failed to parse prompt text as JSON: ${reason}`, this.payload);\n }\n }\n}\n\nexport class ResourceResponseError extends Error {\n readonly response: NativeReadResourceResponse;\n\n constructor(message: string, response: NativeReadResourceResponse) {\n super(message);\n this.name = 'ResourceResponseError';\n this.response = response;\n }\n}\n\nexport class ResourceResponseWrapper {\n private readonly payload: NativeReadResourceResponse;\n\n constructor(payload: NativeReadResourceResponse) {\n this.payload = payload;\n }\n\n raw(): NativeReadResourceResponse {\n return this.payload;\n }\n\n text(): string {\n const entry = this.firstEntry();\n if ('text' in entry && typeof entry.text === 'string') {\n return entry.text;\n }\n if ('blob' in entry && typeof entry.blob === 'string') {\n try {\n return Buffer.from(entry.blob, 'base64').toString('utf8');\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to decode resource blob as UTF-8 text: ${reason}`, this.payload);\n }\n }\n throw new ResourceResponseError('Resource content does not include text or blob data', this.payload);\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n validator(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to parse resource text as JSON: ${reason}`, this.payload);\n }\n }\n\n private firstEntry(): NativeReadResourceResponse['contents'][number] {\n const [entry] = this.payload.contents ?? [];\n if (!entry) {\n throw new ResourceResponseError('Resource response did not include any contents', this.payload);\n }\n return entry;\n }\n}\n\nfunction hasStructuredContent(response: NativeCallToolResponse): response is NativeCallToolResponse & { structuredContent: Record<string, unknown> } {\n return Boolean((response as { structuredContent?: unknown }).structuredContent);\n}\n\nfunction isCompatibilityResult(response: NativeCallToolResponse): response is NativeCallToolResponse & { toolResult: unknown } {\n return hasOwn(response, 'toolResult');\n}\n\nfunction findFirstTextBlock(blocks: ContentBlock[] | undefined): TextContent | undefined {\n if (!Array.isArray(blocks)) {\n return undefined;\n }\n return blocks.find(isTextContent);\n}\n\nfunction collectPromptText(messages: PromptMessage[]): string[] {\n const segments: string[] = [];\n for (const message of messages) {\n const textBlock = isTextContent(message.content) ? message.content : undefined;\n if (textBlock) {\n segments.push(textBlock.text);\n }\n }\n return segments;\n}\n\nfunction isTextContent(block: unknown): block is TextContent {\n return Boolean(block) && typeof block === 'object' && (block as { type?: string }).type === 'text';\n}\n\nconst protoHasOwn = Object.prototype.hasOwnProperty;\n\nfunction hasOwn(target: object, key: PropertyKey): boolean {\n return protoHasOwn.call(target, key);\n}\n\nfunction formatErrorReason(error: unknown): string {\n if (error instanceof Error && typeof error.message === 'string') {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n"],"names":["Buffer","ToolResponseError","Error","message","response","name","ToolResponseWrapper","raw","payload","json","validator","value","resolveJsonPayload","text","isCompatibilityResult","toolResult","throwIfError","textBlock","findFirstTextBlock","content","hasStructuredContent","structuredContent","JSON","parse","error","reason","formatErrorReason","isError","detail","String","PromptResponseError","PromptResponseWrapper","segments","collectPromptText","messages","length","join","textValue","parsed","ResourceResponseError","ResourceResponseWrapper","entry","firstEntry","blob","from","toString","contents","Boolean","hasOwn","blocks","Array","isArray","undefined","find","isTextContent","push","block","type","protoHasOwn","Object","prototype","hasOwnProperty","target","key","call","stringify"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/response-wrappers.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { ContentBlock, PromptMessage, TextContent } from '@modelcontextprotocol/sdk/types.js';\n\nexport type NativeCallToolResponse = Awaited<ReturnType<Client['callTool']>>;\nexport type NativeGetPromptResponse = Awaited<ReturnType<Client['getPrompt']>>;\nexport type NativeReadResourceResponse = Awaited<ReturnType<Client['readResource']>>;\n\nexport type JsonValidator<T> = (value: unknown) => asserts value is T;\n\nexport class ToolResponseError extends Error {\n readonly response: NativeCallToolResponse;\n\n constructor(message: string, response: NativeCallToolResponse) {\n super(message);\n this.name = 'ToolResponseError';\n this.response = response;\n }\n}\n\nexport class ToolResponseWrapper {\n private readonly payload: NativeCallToolResponse;\n\n constructor(payload: NativeCallToolResponse) {\n this.payload = payload;\n }\n\n raw(): NativeCallToolResponse {\n return this.payload;\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const value = this.resolveJsonPayload();\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(value);\n }\n return value as T;\n }\n\n text(): string {\n if (isCompatibilityResult(this.payload)) {\n if (typeof this.payload.toolResult === 'string') {\n return this.payload.toolResult;\n }\n throw new ToolResponseError('Compatibility tool result is not text', this.payload);\n }\n\n this.throwIfError();\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include text content', this.payload);\n }\n\n return textBlock.text;\n }\n\n private resolveJsonPayload(): unknown {\n if (isCompatibilityResult(this.payload)) {\n return this.payload.toolResult;\n }\n\n this.throwIfError();\n\n if (hasStructuredContent(this.payload)) {\n return this.payload.structuredContent;\n }\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include structuredContent or text content', this.payload);\n }\n\n try {\n return JSON.parse(textBlock.text) as unknown;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ToolResponseError(`Failed to parse tool text content as JSON: ${reason}`, this.payload);\n }\n }\n\n private throwIfError(): void {\n if ('isError' in this.payload && this.payload.isError) {\n let detail = typeof this.payload.error === 'object' && this.payload.error && 'message' in this.payload.error ? String((this.payload.error as { message?: unknown }).message ?? '') : '';\n if (!detail) {\n const textBlock = findFirstTextBlock((this.payload.content ?? []) as ContentBlock[]);\n if (textBlock?.text) {\n detail = textBlock.text;\n }\n }\n const message = detail ? `Tool invocation returned an error result: ${detail}` : 'Tool invocation returned an error result';\n throw new ToolResponseError(message, this.payload);\n }\n }\n}\n\nexport class PromptResponseError extends Error {\n readonly response: NativeGetPromptResponse;\n\n constructor(message: string, response: NativeGetPromptResponse) {\n super(message);\n this.name = 'PromptResponseError';\n this.response = response;\n }\n}\n\nexport class PromptResponseWrapper {\n private readonly payload: NativeGetPromptResponse;\n\n constructor(payload: NativeGetPromptResponse) {\n this.payload = payload;\n }\n\n raw(): NativeGetPromptResponse {\n return this.payload;\n }\n\n text(): string {\n const segments = collectPromptText(this.payload.messages);\n if (!segments.length) {\n throw new PromptResponseError('Prompt response did not include text content', this.payload);\n }\n return segments.join('\\n\\n');\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new PromptResponseError(`Failed to parse prompt text as JSON: ${reason}`, this.payload);\n }\n }\n}\n\nexport class ResourceResponseError extends Error {\n readonly response: NativeReadResourceResponse;\n\n constructor(message: string, response: NativeReadResourceResponse) {\n super(message);\n this.name = 'ResourceResponseError';\n this.response = response;\n }\n}\n\nexport class ResourceResponseWrapper {\n private readonly payload: NativeReadResourceResponse;\n\n constructor(payload: NativeReadResourceResponse) {\n this.payload = payload;\n }\n\n raw(): NativeReadResourceResponse {\n return this.payload;\n }\n\n text(): string {\n const entry = this.firstEntry();\n if ('text' in entry && typeof entry.text === 'string') {\n return entry.text;\n }\n if ('blob' in entry && typeof entry.blob === 'string') {\n try {\n return Buffer.from(entry.blob, 'base64').toString('utf8');\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to decode resource blob as UTF-8 text: ${reason}`, this.payload);\n }\n }\n throw new ResourceResponseError('Resource content does not include text or blob data', this.payload);\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to parse resource text as JSON: ${reason}`, this.payload);\n }\n }\n\n private firstEntry(): NativeReadResourceResponse['contents'][number] {\n const [entry] = this.payload.contents ?? [];\n if (!entry) {\n throw new ResourceResponseError('Resource response did not include any contents', this.payload);\n }\n return entry;\n }\n}\n\nfunction hasStructuredContent(response: NativeCallToolResponse): response is NativeCallToolResponse & { structuredContent: Record<string, unknown> } {\n return Boolean((response as { structuredContent?: unknown }).structuredContent);\n}\n\nfunction isCompatibilityResult(response: NativeCallToolResponse): response is NativeCallToolResponse & { toolResult: unknown } {\n return hasOwn(response, 'toolResult');\n}\n\nfunction findFirstTextBlock(blocks: ContentBlock[] | undefined): TextContent | undefined {\n if (!Array.isArray(blocks)) {\n return undefined;\n }\n return blocks.find(isTextContent);\n}\n\nfunction collectPromptText(messages: PromptMessage[]): string[] {\n const segments: string[] = [];\n for (const message of messages) {\n const textBlock = isTextContent(message.content) ? message.content : undefined;\n if (textBlock) {\n segments.push(textBlock.text);\n }\n }\n return segments;\n}\n\nfunction isTextContent(block: unknown): block is TextContent {\n return Boolean(block) && typeof block === 'object' && (block as { type?: string }).type === 'text';\n}\n\nconst protoHasOwn = Object.prototype.hasOwnProperty;\n\nfunction hasOwn(target: object, key: PropertyKey): boolean {\n return protoHasOwn.call(target, key);\n}\n\nfunction formatErrorReason(error: unknown): string {\n if (error instanceof Error && typeof error.message === 'string') {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n"],"names":["Buffer","ToolResponseError","Error","message","response","name","ToolResponseWrapper","raw","payload","json","validator","value","resolveJsonPayload","assertValid","text","isCompatibilityResult","toolResult","throwIfError","textBlock","findFirstTextBlock","content","hasStructuredContent","structuredContent","JSON","parse","error","reason","formatErrorReason","isError","detail","String","PromptResponseError","PromptResponseWrapper","segments","collectPromptText","messages","length","join","textValue","parsed","ResourceResponseError","ResourceResponseWrapper","entry","firstEntry","blob","from","toString","contents","Boolean","hasOwn","blocks","Array","isArray","undefined","find","isTextContent","push","block","type","protoHasOwn","Object","prototype","hasOwnProperty","target","key","call","stringify"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/search/index.ts"],"sourcesContent":["/**\n * Search module for MCP capability discovery\n */\n\nexport type { CapabilityClient } from './search.ts';\nexport { buildCapabilityIndex, search, searchCapabilities } from './search.ts';\nexport type {\n CapabilityIndex,\n CapabilityType,\n IndexedCapability,\n IndexedPrompt,\n IndexedResource,\n IndexedTool,\n SearchField,\n SearchOptions,\n SearchResponse,\n SearchResult,\n} from './types.ts';\n"],"names":["buildCapabilityIndex","search","searchCapabilities"],"mappings":"AAAA;;CAEC,GAGD,SAASA,oBAAoB,EAAEC,MAAM,EAAEC,kBAAkB,QAAQ,cAAc"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/index.ts"],"sourcesContent":["/**\n * Search module for MCP capability discovery\n */\n\nexport type { CapabilityClient } from './search.ts';\nexport { buildCapabilityIndex, search, searchCapabilities } from './search.ts';\nexport type {\n CapabilityIndex,\n CapabilityType,\n IndexedCapability,\n IndexedPrompt,\n IndexedResource,\n IndexedTool,\n SearchField,\n SearchOptions,\n SearchResponse,\n SearchResult,\n} from './types.ts';\n"],"names":["buildCapabilityIndex","search","searchCapabilities"],"mappings":"AAAA;;CAEC,GAGD,SAASA,oBAAoB,EAAEC,MAAM,EAAEC,kBAAkB,QAAQ,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","propName","prop","Object","entries","join","extractArgumentsText","args","Array","isArray","map","arg","name","buildCapabilityIndex","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","Promise","all","listTools","catch","listPrompts","listResources","tools","tool","type","server","schemaText","prompts","prompt","argumentsText","arguments","resources","resource","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","searchCapabilities","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice","search"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","propName","prop","Object","entries","join","extractArgumentsText","args","Array","isArray","map","arg","name","buildCapabilityIndex","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","Promise","all","listTools","catch","listPrompts","listResources","tools","tool","type","server","schemaText","prompts","prompt","argumentsText","arguments","resources","resource","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","searchCapabilities","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice","search"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/search/types.ts"],"sourcesContent":["/**\n * Search types for MCP capability discovery\n *\n * Enables agents to discover tools, prompts, and resources without\n * loading full schemas into context.\n */\n\nimport type { PromptArgument } from '../connection/types.ts';\n\n/**\n * Types of MCP capabilities that can be searched\n */\nexport type CapabilityType = 'tool' | 'prompt' | 'resource';\n\n/**\n * Fields that can be searched within capabilities\n */\nexport type SearchField = 'name' | 'description' | 'schema' | 'server';\n\n/**\n * Options for configuring search behavior\n */\nexport interface SearchOptions {\n /**\n * Filter to specific capability types\n * @default ['tool', 'prompt', 'resource']\n */\n types?: CapabilityType[];\n\n /**\n * Filter to specific servers by name\n * @default all servers in config\n */\n servers?: string[];\n\n /**\n * Which fields to search within\n * @default ['name', 'description', 'schema']\n */\n searchFields?: SearchField[];\n\n /**\n * Maximum number of results to return\n * @default 20\n */\n limit?: number;\n\n /**\n * Minimum relevance score (0-1) for results\n * @default 0\n */\n threshold?: number;\n}\n\n/**\n * A single search result representing a matched capability\n */\nexport interface SearchResult {\n /** The type of capability */\n type: CapabilityType;\n\n /** The server that provides this capability */\n server: string;\n\n /** The name of the capability */\n name: string;\n\n /** Human-readable description (may be truncated) */\n description: string | undefined;\n\n /** Which fields matched the search query */\n matchedOn: string[];\n\n /** Relevance score from 0 (low) to 1 (high) */\n score: number;\n}\n\n/**\n * Complete search response\n */\nexport interface SearchResponse {\n /** The original search query */\n query: string;\n\n /** Matching results, sorted by relevance */\n results: SearchResult[];\n\n /** Total number of matches before limit was applied */\n total: number;\n}\n\n/**\n * Internal representation of a tool for indexing\n */\nexport interface IndexedTool {\n type: 'tool';\n server: string;\n name: string;\n description: string | undefined;\n /** Flattened searchable text from inputSchema property descriptions */\n schemaText: string;\n}\n\n/**\n * Internal representation of a prompt for indexing\n */\nexport interface IndexedPrompt {\n type: 'prompt';\n server: string;\n name: string;\n description: string | undefined;\n /** Flattened searchable text from arguments */\n argumentsText: string;\n arguments: PromptArgument[] | undefined;\n}\n\n/**\n * Internal representation of a resource for indexing\n */\nexport interface IndexedResource {\n type: 'resource';\n server: string;\n name: string;\n description: string | undefined;\n uri: string;\n mimeType: string | undefined;\n}\n\n/**\n * Union of all indexed capability types\n */\nexport type IndexedCapability = IndexedTool | IndexedPrompt | IndexedResource;\n\n/**\n * Index containing all capabilities from connected servers\n */\nexport interface CapabilityIndex {\n /** All indexed capabilities */\n capabilities: IndexedCapability[];\n\n /** Servers that were indexed */\n servers: string[];\n\n /** When the index was created */\n indexedAt: Date;\n}\n"],"names":[],"mappings":"AAAA;;;;;CAKC,GAgID;;CAEC,GACD,WASC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/types.ts"],"sourcesContent":["/**\n * Search types for MCP capability discovery\n *\n * Enables agents to discover tools, prompts, and resources without\n * loading full schemas into context.\n */\n\nimport type { PromptArgument } from '../connection/types.ts';\n\n/**\n * Types of MCP capabilities that can be searched\n */\nexport type CapabilityType = 'tool' | 'prompt' | 'resource';\n\n/**\n * Fields that can be searched within capabilities\n */\nexport type SearchField = 'name' | 'description' | 'schema' | 'server';\n\n/**\n * Options for configuring search behavior\n */\nexport interface SearchOptions {\n /**\n * Filter to specific capability types\n * @default ['tool', 'prompt', 'resource']\n */\n types?: CapabilityType[];\n\n /**\n * Filter to specific servers by name\n * @default all servers in config\n */\n servers?: string[];\n\n /**\n * Which fields to search within\n * @default ['name', 'description', 'schema']\n */\n searchFields?: SearchField[];\n\n /**\n * Maximum number of results to return\n * @default 20\n */\n limit?: number;\n\n /**\n * Minimum relevance score (0-1) for results\n * @default 0\n */\n threshold?: number;\n}\n\n/**\n * A single search result representing a matched capability\n */\nexport interface SearchResult {\n /** The type of capability */\n type: CapabilityType;\n\n /** The server that provides this capability */\n server: string;\n\n /** The name of the capability */\n name: string;\n\n /** Human-readable description (may be truncated) */\n description: string | undefined;\n\n /** Which fields matched the search query */\n matchedOn: string[];\n\n /** Relevance score from 0 (low) to 1 (high) */\n score: number;\n}\n\n/**\n * Complete search response\n */\nexport interface SearchResponse {\n /** The original search query */\n query: string;\n\n /** Matching results, sorted by relevance */\n results: SearchResult[];\n\n /** Total number of matches before limit was applied */\n total: number;\n}\n\n/**\n * Internal representation of a tool for indexing\n */\nexport interface IndexedTool {\n type: 'tool';\n server: string;\n name: string;\n description: string | undefined;\n /** Flattened searchable text from inputSchema property descriptions */\n schemaText: string;\n}\n\n/**\n * Internal representation of a prompt for indexing\n */\nexport interface IndexedPrompt {\n type: 'prompt';\n server: string;\n name: string;\n description: string | undefined;\n /** Flattened searchable text from arguments */\n argumentsText: string;\n arguments: PromptArgument[] | undefined;\n}\n\n/**\n * Internal representation of a resource for indexing\n */\nexport interface IndexedResource {\n type: 'resource';\n server: string;\n name: string;\n description: string | undefined;\n uri: string;\n mimeType: string | undefined;\n}\n\n/**\n * Union of all indexed capability types\n */\nexport type IndexedCapability = IndexedTool | IndexedPrompt | IndexedResource;\n\n/**\n * Index containing all capabilities from connected servers\n */\nexport interface CapabilityIndex {\n /** All indexed capabilities */\n capabilities: IndexedCapability[];\n\n /** Servers that were indexed */\n servers: string[];\n\n /** When the index was created */\n indexedAt: Date;\n}\n"],"names":[],"mappings":"AAAA;;;;;CAKC,GAgID;;CAEC,GACD,WASC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/client/src/spawn/spawn-server.ts"],"sourcesContent":["/**\n * Low-level single server spawning utilities.\n * Provides core process spawning with path resolution, environment management, and lifecycle control.\n */\n\nimport { type ChildProcess, type SpawnOptions, type StdioOptions, spawn } from 'child_process';\nimport * as process from 'process';\nimport { logger } from '../utils/logger.ts';\nimport { resolveArgsPaths } from '../utils/path-utils.ts';\n\n/**\n * Options for spawning a single server process.\n * @internal\n */\nexport interface SpawnProcessOptions {\n /** Server name for logging */\n name: string;\n /** Command to execute (e.g., 'node', 'npx') */\n command: string;\n /** Command arguments (paths will be resolved relative to cwd) */\n args?: string[];\n /** Working directory (must be absolute path) */\n cwd?: string;\n /** Additional environment variables (merged with process.env) */\n env?: Record<string, string>;\n /** Standard I/O configuration */\n stdio?: StdioOptions;\n /** Use shell for command execution (default: false, true on Windows) */\n shell?: boolean;\n}\n\n/**\n * Handle to a spawned server process.\n * Provides access to the process, resolved config, and lifecycle control.\n * @hidden\n */\nexport interface ServerProcess {\n /**\n * The resolved server configuration that was actually used.\n * Useful for debugging and understanding what was spawned.\n */\n config: {\n name: string;\n command: string;\n args: string[];\n cwd: string;\n env: Record<string, string>;\n stdio: StdioOptions;\n shell: boolean;\n };\n\n /**\n * The spawned child process.\n */\n process: ChildProcess;\n\n /**\n * Close the server gracefully.\n * Sends the specified signal (default: SIGINT), then SIGKILL after timeout.\n *\n * @param signal - Signal to send (default: SIGINT)\n * @param opts - Options including timeout\n * @returns Promise resolving to whether the process timed out and was force-killed\n */\n close: (signal?: NodeJS.Signals, opts?: { timeoutMs?: number }) => Promise<{ timedOut: boolean; killed: boolean }>;\n}\n\n/**\n * Normalize environment variables by merging with process.env and filtering undefined values.\n */\nfunction normalizeEnv(env?: Record<string, string>): Record<string, string> {\n const merged = { ...process.env, ...(env || {}) };\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(merged)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Spawn a single server process with path resolution and environment management.\n *\n * @internal\n * @param opts - Server spawn options\n * @returns ServerProcess handle with resolved config, process, and stop function\n *\n * @example\n * const handle = spawnProcess({\n * name: 'echo',\n * command: 'node',\n * args: ['./bin/server.js', '--port', '3000'],\n * cwd: '/home/user/project/test/lib/servers/echo',\n * env: { LOG_LEVEL: 'error' }\n * });\n *\n * // Later...\n * await handle.close();\n */\nexport function spawnProcess(opts: SpawnProcessOptions): ServerProcess {\n const name = opts.name;\n const command = opts.command;\n const cwd = opts.cwd ?? process.cwd();\n const stdio = opts.stdio ?? 'inherit';\n const shell = opts.shell ?? process.platform === 'win32';\n\n // Resolve paths in args relative to the working directory\n const args = opts.args ? resolveArgsPaths(opts.args, cwd) : [];\n\n // Merge environment variables\n const env = normalizeEnv(opts.env);\n\n // Create resolved config for return value\n const resolvedConfig = {\n name,\n command,\n args,\n cwd,\n env,\n stdio,\n shell,\n };\n\n // Log spawn operation\n logger.info(`[${name}] → ${command} ${args.join(' ')}`);\n\n // Spawn the process\n const spawnOpts: SpawnOptions = { cwd, env, stdio, shell };\n const child = spawn(command, args, spawnOpts);\n\n // Pipe stdio if not inherited\n if (child.stderr)\n child.stderr.on('data', (chunk) => {\n process.stderr.write(chunk);\n });\n\n // Attach lifecycle logging\n child.on('exit', (code, sig) => logger.info(`[${name}] exited (code=${code}, signal=${sig || 'none'})`));\n child.on('error', (err) => logger.info(`[${name}] process error: ${err.message}`));\n\n // Create stop function with graceful shutdown\n const stop = async (signal: NodeJS.Signals = 'SIGINT', opts: { timeoutMs?: number } = {}): Promise<{ timedOut: boolean; killed: boolean }> => {\n // If already exited, return immediately\n if (child.exitCode !== null || child.signalCode !== null) {\n return { timedOut: false, killed: false };\n }\n\n const timeoutMs = opts.timeoutMs ?? 500;\n\n // Wait for 'close' event (process exit + stdio streams closed)\n // This is better than 'exit' because it ensures stdio is fully cleaned up\n const closePromise = new Promise<{ timedOut: boolean; killed: boolean }>((resolve) => {\n let isResolved = false;\n let wasKilled = false;\n\n const resolveOnce = (timedOut: boolean) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n resolve({ timedOut, killed: wasKilled });\n };\n\n // Set timeout for forceful kill\n const timeout = setTimeout(() => {\n try {\n // Check again before SIGKILL\n if (child.exitCode === null && !child.killed) {\n child.kill('SIGKILL');\n wasKilled = true;\n }\n } catch (_) {}\n // Even if kill fails, resolve\n resolveOnce(true);\n }, timeoutMs);\n\n // Listen for 'close' event (not 'exit') to wait for stdio close\n child.once('close', () => {\n resolveOnce(false);\n });\n\n // Also listen for 'error' event in case spawn failed\n // This prevents promise from hanging forever if process never started\n child.once('error', () => {\n resolveOnce(false);\n });\n\n // Send graceful shutdown signal\n try {\n // Check one more time before killing\n if (child.exitCode !== null) {\n resolveOnce(false);\n return;\n }\n\n const killed = child.kill(signal);\n // If kill returned false, process already exited\n if (!killed) {\n resolveOnce(false);\n }\n } catch (_err) {\n // If kill throws, process is gone or unreachable\n resolveOnce(false);\n }\n });\n\n return closePromise;\n };\n\n return {\n config: resolvedConfig,\n process: child,\n close: stop,\n };\n}\n"],"names":["spawn","process","logger","resolveArgsPaths","normalizeEnv","env","merged","result","key","value","Object","entries","undefined","spawnProcess","opts","name","command","cwd","stdio","shell","platform","args","resolvedConfig","info","join","spawnOpts","child","stderr","on","chunk","write","code","sig","err","message","stop","signal","exitCode","signalCode","timedOut","killed","timeoutMs","closePromise","Promise","resolve","isResolved","wasKilled","resolveOnce","clearTimeout","timeout","setTimeout","kill","_","once","_err","config","close"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/spawn/spawn-server.ts"],"sourcesContent":["/**\n * Low-level single server spawning utilities.\n * Provides core process spawning with path resolution, environment management, and lifecycle control.\n */\n\nimport { type ChildProcess, type SpawnOptions, type StdioOptions, spawn } from 'child_process';\nimport * as process from 'process';\nimport { logger } from '../utils/logger.ts';\nimport { resolveArgsPaths } from '../utils/path-utils.ts';\n\n/**\n * Options for spawning a single server process.\n * @internal\n */\nexport interface SpawnProcessOptions {\n /** Server name for logging */\n name: string;\n /** Command to execute (e.g., 'node', 'npx') */\n command: string;\n /** Command arguments (paths will be resolved relative to cwd) */\n args?: string[];\n /** Working directory (must be absolute path) */\n cwd?: string;\n /** Additional environment variables (merged with process.env) */\n env?: Record<string, string>;\n /** Standard I/O configuration */\n stdio?: StdioOptions;\n /** Use shell for command execution (default: false, true on Windows) */\n shell?: boolean;\n}\n\n/**\n * Handle to a spawned server process.\n * Provides access to the process, resolved config, and lifecycle control.\n * @hidden\n */\nexport interface ServerProcess {\n /**\n * The resolved server configuration that was actually used.\n * Useful for debugging and understanding what was spawned.\n */\n config: {\n name: string;\n command: string;\n args: string[];\n cwd: string;\n env: Record<string, string>;\n stdio: StdioOptions;\n shell: boolean;\n };\n\n /**\n * The spawned child process.\n */\n process: ChildProcess;\n\n /**\n * Close the server gracefully.\n * Sends the specified signal (default: SIGINT), then SIGKILL after timeout.\n *\n * @param signal - Signal to send (default: SIGINT)\n * @param opts - Options including timeout\n * @returns Promise resolving to whether the process timed out and was force-killed\n */\n close: (signal?: NodeJS.Signals, opts?: { timeoutMs?: number }) => Promise<{ timedOut: boolean; killed: boolean }>;\n}\n\n/**\n * Normalize environment variables by merging with process.env and filtering undefined values.\n */\nfunction normalizeEnv(env?: Record<string, string>): Record<string, string> {\n const merged = { ...process.env, ...(env || {}) };\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(merged)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Spawn a single server process with path resolution and environment management.\n *\n * @internal\n * @param opts - Server spawn options\n * @returns ServerProcess handle with resolved config, process, and stop function\n *\n * @example\n * const handle = spawnProcess({\n * name: 'echo',\n * command: 'node',\n * args: ['./bin/server.js', '--port', '3000'],\n * cwd: '/home/user/project/test/lib/servers/echo',\n * env: { LOG_LEVEL: 'error' }\n * });\n *\n * // Later...\n * await handle.close();\n */\nexport function spawnProcess(opts: SpawnProcessOptions): ServerProcess {\n const name = opts.name;\n const command = opts.command;\n const cwd = opts.cwd ?? process.cwd();\n const stdio = opts.stdio ?? 'inherit';\n const shell = opts.shell ?? process.platform === 'win32';\n\n // Resolve paths in args relative to the working directory\n const args = opts.args ? resolveArgsPaths(opts.args, cwd) : [];\n\n // Merge environment variables\n const env = normalizeEnv(opts.env);\n\n // Create resolved config for return value\n const resolvedConfig = {\n name,\n command,\n args,\n cwd,\n env,\n stdio,\n shell,\n };\n\n // Log spawn operation\n logger.info(`[${name}] → ${command} ${args.join(' ')}`);\n\n // Spawn the process\n const spawnOpts: SpawnOptions = { cwd, env, stdio, shell };\n const child = spawn(command, args, spawnOpts);\n\n // Pipe stdio if not inherited\n if (child.stderr)\n child.stderr.on('data', (chunk) => {\n process.stderr.write(chunk);\n });\n\n // Attach lifecycle logging\n child.on('exit', (code, sig) => logger.info(`[${name}] exited (code=${code}, signal=${sig || 'none'})`));\n child.on('error', (err) => logger.info(`[${name}] process error: ${err.message}`));\n\n // Create stop function with graceful shutdown\n const stop = async (signal: NodeJS.Signals = 'SIGINT', opts: { timeoutMs?: number } = {}): Promise<{ timedOut: boolean; killed: boolean }> => {\n // If already exited, return immediately\n if (child.exitCode !== null || child.signalCode !== null) {\n return { timedOut: false, killed: false };\n }\n\n const timeoutMs = opts.timeoutMs ?? 500;\n\n // Wait for 'close' event (process exit + stdio streams closed)\n // This is better than 'exit' because it ensures stdio is fully cleaned up\n const closePromise = new Promise<{ timedOut: boolean; killed: boolean }>((resolve) => {\n let isResolved = false;\n let wasKilled = false;\n\n const resolveOnce = (timedOut: boolean) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n resolve({ timedOut, killed: wasKilled });\n };\n\n // Set timeout for forceful kill\n const timeout = setTimeout(() => {\n try {\n // Check again before SIGKILL\n if (child.exitCode === null && !child.killed) {\n child.kill('SIGKILL');\n wasKilled = true;\n }\n } catch (_) {}\n // Even if kill fails, resolve\n resolveOnce(true);\n }, timeoutMs);\n\n // Listen for 'close' event (not 'exit') to wait for stdio close\n child.once('close', () => {\n resolveOnce(false);\n });\n\n // Also listen for 'error' event in case spawn failed\n // This prevents promise from hanging forever if process never started\n child.once('error', () => {\n resolveOnce(false);\n });\n\n // Send graceful shutdown signal\n try {\n // Check one more time before killing\n if (child.exitCode !== null) {\n resolveOnce(false);\n return;\n }\n\n const killed = child.kill(signal);\n // If kill returned false, process already exited\n if (!killed) {\n resolveOnce(false);\n }\n } catch (_err) {\n // If kill throws, process is gone or unreachable\n resolveOnce(false);\n }\n });\n\n return closePromise;\n };\n\n return {\n config: resolvedConfig,\n process: child,\n close: stop,\n };\n}\n"],"names":["spawn","process","logger","resolveArgsPaths","normalizeEnv","env","merged","result","key","value","Object","entries","undefined","spawnProcess","opts","name","command","cwd","stdio","shell","platform","args","resolvedConfig","info","join","spawnOpts","child","stderr","on","chunk","write","code","sig","err","message","stop","signal","exitCode","signalCode","timedOut","killed","timeoutMs","closePromise","Promise","resolve","isResolved","wasKilled","resolveOnce","clearTimeout","timeout","setTimeout","kill","_","once","_err","config","close"],"mappings":"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"}