@mcp-z/client 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/cjs/connection/connect-client.d.cts +11 -0
- package/dist/cjs/connection/connect-client.d.ts +11 -0
- package/dist/cjs/connection/connect-client.js +12 -7
- package/dist/cjs/connection/connect-client.js.map +1 -1
- package/dist/cjs/index.d.cts +2 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/connection/connect-client.d.ts +11 -0
- package/dist/esm/connection/connect-client.js +20 -6
- package/dist/esm/connection/connect-client.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,6 +156,28 @@ const client = await registry.connect('todoist', {
|
|
|
156
156
|
});
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
+
## Protocol version negotiation
|
|
160
|
+
|
|
161
|
+
By default a connect performs the plain 2025 MCP connect sequence. Pass `versionNegotiation` to negotiate the protocol revision instead:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// Probe the server first; connect at the newest revision it offers,
|
|
165
|
+
// falling back to the 2025 sequence when it cannot serve the modern era
|
|
166
|
+
const client = await registry.connect('modern-server', {
|
|
167
|
+
versionNegotiation: { mode: 'auto' }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Require the 2026-07-28 revision; a server that cannot serve it fails
|
|
171
|
+
// the connect with SdkErrorCode.EraNegotiationFailed
|
|
172
|
+
const pinned = await registry.connect('strict-server', {
|
|
173
|
+
versionNegotiation: { mode: { pin: '2026-07-28' } }
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
After connecting, `client.getProtocolEra()` returns `'modern'` or `'legacy'` and `client.getNegotiatedProtocolVersion()` the revision the server settled on.
|
|
178
|
+
|
|
179
|
+
Note: with `mode: 'auto'` against a stdio server, a legacy server that never answers the `server/discover` probe costs the full request timeout (60s) before the client falls back to the 2025 sequence. The probe ends fast when the server answers it at all — with any reply, even a "method not found" error.
|
|
180
|
+
|
|
159
181
|
## Requirements
|
|
160
182
|
|
|
161
183
|
- Node.js >= 22
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Helper to connect MCP SDK clients to servers with intelligent transport inference.
|
|
5
5
|
* Automatically detects transport type from URL protocol or type field.
|
|
6
6
|
*/
|
|
7
|
+
import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
7
8
|
import { Client } from '@modelcontextprotocol/client';
|
|
8
9
|
import { type DcrAuthenticatorOptions } from '../dcr/index.js';
|
|
9
10
|
import type { ServerProcess } from '../spawn/spawn-server.js';
|
|
@@ -32,6 +33,15 @@ import { type Logger } from '../utils/logger.js';
|
|
|
32
33
|
*
|
|
33
34
|
* @param registryOrConfig - Result from createServerRegistry() or servers config object
|
|
34
35
|
* @param serverName - Server name from servers config
|
|
36
|
+
* @param options - Connection options (see below)
|
|
37
|
+
* @param options.dcrAuthenticator - DCR authenticator options
|
|
38
|
+
* @param options.logger - Logger for connection diagnostics
|
|
39
|
+
* @param options.versionNegotiation - SDK protocol version negotiation (protocol revision
|
|
40
|
+
* 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:
|
|
41
|
+
* the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and
|
|
42
|
+
* fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`
|
|
43
|
+
* to require the pinned revision (a server that cannot serve it fails the connect with
|
|
44
|
+
* a typed era-negotiation error).
|
|
35
45
|
* @returns Connected MCP SDK Client (guaranteed ready)
|
|
36
46
|
*
|
|
37
47
|
* @example
|
|
@@ -54,5 +64,6 @@ import { type Logger } from '../utils/logger.js';
|
|
|
54
64
|
export declare function connectMcpClient(registryOrConfig: RegistryLike | ServersConfig, serverName: string, options?: {
|
|
55
65
|
dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
|
|
56
66
|
logger?: Logger;
|
|
67
|
+
versionNegotiation?: VersionNegotiationOptions;
|
|
57
68
|
}): Promise<Client>;
|
|
58
69
|
export {};
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Helper to connect MCP SDK clients to servers with intelligent transport inference.
|
|
5
5
|
* Automatically detects transport type from URL protocol or type field.
|
|
6
6
|
*/
|
|
7
|
+
import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
7
8
|
import { Client } from '@modelcontextprotocol/client';
|
|
8
9
|
import { type DcrAuthenticatorOptions } from '../dcr/index.js';
|
|
9
10
|
import type { ServerProcess } from '../spawn/spawn-server.js';
|
|
@@ -32,6 +33,15 @@ import { type Logger } from '../utils/logger.js';
|
|
|
32
33
|
*
|
|
33
34
|
* @param registryOrConfig - Result from createServerRegistry() or servers config object
|
|
34
35
|
* @param serverName - Server name from servers config
|
|
36
|
+
* @param options - Connection options (see below)
|
|
37
|
+
* @param options.dcrAuthenticator - DCR authenticator options
|
|
38
|
+
* @param options.logger - Logger for connection diagnostics
|
|
39
|
+
* @param options.versionNegotiation - SDK protocol version negotiation (protocol revision
|
|
40
|
+
* 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:
|
|
41
|
+
* the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and
|
|
42
|
+
* fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`
|
|
43
|
+
* to require the pinned revision (a server that cannot serve it fails the connect with
|
|
44
|
+
* a typed era-negotiation error).
|
|
35
45
|
* @returns Connected MCP SDK Client (guaranteed ready)
|
|
36
46
|
*
|
|
37
47
|
* @example
|
|
@@ -54,5 +64,6 @@ import { type Logger } from '../utils/logger.js';
|
|
|
54
64
|
export declare function connectMcpClient(registryOrConfig: RegistryLike | ServersConfig, serverName: string, options?: {
|
|
55
65
|
dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
|
|
56
66
|
logger?: Logger;
|
|
67
|
+
versionNegotiation?: VersionNegotiationOptions;
|
|
57
68
|
}): Promise<Client>;
|
|
58
69
|
export {};
|
|
@@ -253,7 +253,7 @@ function _ts_generator(thisArg, body) {
|
|
|
253
253
|
}
|
|
254
254
|
function connectMcpClient(registryOrConfig, serverName, options) {
|
|
255
255
|
return _async_to_generator(function() {
|
|
256
|
-
var _ref, isRegistry, serversConfig, registry, logger, serverConfig, available, transportType, client, serverHandle, transport, transport1, isSpawnedHttp, url, mcpServerUrl, capabilities, authToken, port, redirectUri, authenticator, tokens, staticHeaders, dcrHeaders, mergedHeaders, transportOptions, transport2, error, errorMessage, cause, isConnectionRefused, shouldFallback, sseClient, staticHeaders1, dcrHeaders1, mergedHeaders1, sseTransportOptions, sseTransport, sseError;
|
|
256
|
+
var _ref, isRegistry, serversConfig, registry, logger, serverConfig, available, transportType, clientOptions, client, serverHandle, transport, transport1, isSpawnedHttp, url, mcpServerUrl, capabilities, authToken, port, redirectUri, authenticator, tokens, staticHeaders, dcrHeaders, mergedHeaders, transportOptions, transport2, error, errorMessage, cause, isConnectionRefused, shouldFallback, sseClient, staticHeaders1, dcrHeaders1, mergedHeaders1, sseTransportOptions, sseTransport, sseError;
|
|
257
257
|
return _ts_generator(this, function(_state) {
|
|
258
258
|
switch(_state.label){
|
|
259
259
|
case 0:
|
|
@@ -269,13 +269,20 @@ function connectMcpClient(registryOrConfig, serverName, options) {
|
|
|
269
269
|
}
|
|
270
270
|
// Infer transport type with validation
|
|
271
271
|
transportType = inferTransportType(serverConfig);
|
|
272
|
+
// SDK client options for both transports (main + SSE fallback). versionNegotiation is
|
|
273
|
+
// omitted rather than set to undefined so the default stays the SDK's 'legacy' mode —
|
|
274
|
+
// the plain 2025 connect sequence — for callers that do not pass it.
|
|
275
|
+
clientOptions = {
|
|
276
|
+
capabilities: {}
|
|
277
|
+
};
|
|
278
|
+
if ((options === null || options === void 0 ? void 0 : options.versionNegotiation) !== undefined) {
|
|
279
|
+
clientOptions.versionNegotiation = options.versionNegotiation;
|
|
280
|
+
}
|
|
272
281
|
// Create MCP client
|
|
273
282
|
client = new _client.Client({
|
|
274
283
|
name: 'mcp-cli-client',
|
|
275
284
|
version: '1.0.0'
|
|
276
|
-
},
|
|
277
|
-
capabilities: {}
|
|
278
|
-
});
|
|
285
|
+
}, clientOptions);
|
|
279
286
|
if (!(transportType === 'stdio')) return [
|
|
280
287
|
3,
|
|
281
288
|
5
|
|
@@ -462,9 +469,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
|
|
|
462
469
|
sseClient = new _client.Client({
|
|
463
470
|
name: 'mcp-cli-client',
|
|
464
471
|
version: '1.0.0'
|
|
465
|
-
},
|
|
466
|
-
capabilities: {}
|
|
467
|
-
});
|
|
472
|
+
}, clientOptions);
|
|
468
473
|
// SSE transport with merged headers (static + DCR auth)
|
|
469
474
|
// Reuse the same header merging logic as Streamable HTTP
|
|
470
475
|
staticHeaders1 = serverConfig.headers || {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport type { Transport } from '@modelcontextprotocol/client';\nimport { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { StdioClientTransport } from '@modelcontextprotocol/client/stdio';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport { normalizeUrl } from '../lib/url-utils.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n // The canonical MCP server URI, path segment and all. Both calls below need\n // the server's identity, not its deployment root: discovery uses the path to\n // find resource-specific metadata (RFC 9728 sub-path), and the authenticator\n // audience-binds tokens to it (RFC 8707). Handing either the `/mcp`-stripped\n // base names a different resource, which authorization servers that validate\n // the `resource` indicator reject as `invalid_target`.\n const mcpServerUrl = normalizeUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(mcpServerUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(mcpServerUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["connectMcpClient","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","inferTransportType","config","type","url","URL","protocol","registryOrConfig","serverName","options","isRegistry","serversConfig","registry","logger","serverConfig","available","transportType","client","serverHandle","transport","isSpawnedHttp","mcpServerUrl","capabilities","authToken","port","redirectUri","authenticator","tokens","staticHeaders","dcrHeaders","mergedHeaders","transportOptions","error","errorMessage","cause","isConnectionRefused","shouldFallback","sseClient","sseTransportOptions","sseTransport","sseError","servers","Map","undefined","defaultLogger","Object","keys","join","Client","name","version","get","ExistingProcessTransport","process","connect","command","StdioClientTransport","args","env","has","debug","waitForHttpReady","normalizeUrl","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","supportsDcr","getPort","DcrAuthenticator","headless","dcrAuthenticator","ensureAuthenticated","accessToken","headers","Authorization","length","requestInit","StreamableHTTPClientTransport","message","String","code","includes","close","catch","warn","SSEClientTransport","all"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport type { ClientOptions, Transport, VersionNegotiationOptions } from '@modelcontextprotocol/client';\nimport { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { StdioClientTransport } from '@modelcontextprotocol/client/stdio';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport { normalizeUrl } from '../lib/url-utils.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @param options - Connection options (see below)\n * @param options.dcrAuthenticator - DCR authenticator options\n * @param options.logger - Logger for connection diagnostics\n * @param options.versionNegotiation - SDK protocol version negotiation (protocol revision\n * 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:\n * the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and\n * fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`\n * to require the pinned revision (a server that cannot serve it fails the connect with\n * a typed era-negotiation error).\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n versionNegotiation?: VersionNegotiationOptions;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // SDK client options for both transports (main + SSE fallback). versionNegotiation is\n // omitted rather than set to undefined so the default stays the SDK's 'legacy' mode —\n // the plain 2025 connect sequence — for callers that do not pass it.\n const clientOptions: ClientOptions = { capabilities: {} };\n if (options?.versionNegotiation !== undefined) {\n clientOptions.versionNegotiation = options.versionNegotiation;\n }\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, clientOptions);\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n // The canonical MCP server URI, path segment and all. Both calls below need\n // the server's identity, not its deployment root: discovery uses the path to\n // find resource-specific metadata (RFC 9728 sub-path), and the authenticator\n // audience-binds tokens to it (RFC 8707). Handing either the `/mcp`-stripped\n // base names a different resource, which authorization servers that validate\n // the `resource` indicator reject as `invalid_target`.\n const mcpServerUrl = normalizeUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(mcpServerUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(mcpServerUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, clientOptions);\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["connectMcpClient","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","inferTransportType","config","type","url","URL","protocol","registryOrConfig","serverName","options","isRegistry","serversConfig","registry","logger","serverConfig","available","transportType","clientOptions","client","serverHandle","transport","isSpawnedHttp","mcpServerUrl","capabilities","authToken","port","redirectUri","authenticator","tokens","staticHeaders","dcrHeaders","mergedHeaders","transportOptions","error","errorMessage","cause","isConnectionRefused","shouldFallback","sseClient","sseTransportOptions","sseTransport","sseError","servers","Map","undefined","defaultLogger","Object","keys","join","versionNegotiation","Client","name","version","get","ExistingProcessTransport","process","connect","command","StdioClientTransport","args","env","has","debug","waitForHttpReady","normalizeUrl","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","supportsDcr","getPort","DcrAuthenticator","headless","dcrAuthenticator","ensureAuthenticated","accessToken","headers","Authorization","length","requestInit","StreamableHTTPClientTransport","message","String","code","includes","close","catch","warn","SSEClientTransport","all"],"mappings":"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"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @mcp-z/client - MCP Client Library
|
|
3
3
|
*/
|
|
4
|
+
export type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
5
|
+
export { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';
|
|
4
6
|
export type { McpServerEntry, StartConfig } from '../schemas/servers.d.js';
|
|
5
7
|
export { probeAuthCapabilities } from './auth/capability-discovery.js';
|
|
6
8
|
export { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.js';
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @mcp-z/client - MCP Client Library
|
|
3
3
|
*/
|
|
4
|
+
export type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
5
|
+
export { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';
|
|
4
6
|
export type { McpServerEntry, StartConfig } from '../schemas/servers.d.js';
|
|
5
7
|
export { probeAuthCapabilities } from './auth/capability-discovery.js';
|
|
6
8
|
export { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @mcp-z/client - MCP Client Library
|
|
3
|
-
*/
|
|
4
|
-
"use strict";
|
|
3
|
+
*/ "use strict";
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
@@ -39,6 +38,12 @@ _export(exports, {
|
|
|
39
38
|
get ResourceResponseWrapper () {
|
|
40
39
|
return _responsewrappersts.ResourceResponseWrapper;
|
|
41
40
|
},
|
|
41
|
+
get SdkError () {
|
|
42
|
+
return _client.SdkError;
|
|
43
|
+
},
|
|
44
|
+
get SdkErrorCode () {
|
|
45
|
+
return _client.SdkErrorCode;
|
|
46
|
+
},
|
|
42
47
|
get ToolResponseError () {
|
|
43
48
|
return _responsewrappersts.ToolResponseError;
|
|
44
49
|
},
|
|
@@ -85,6 +90,7 @@ _export(exports, {
|
|
|
85
90
|
return _validateconfigts.validateServers;
|
|
86
91
|
}
|
|
87
92
|
});
|
|
93
|
+
var _client = require("@modelcontextprotocol/client");
|
|
88
94
|
var _capabilitydiscoveryts = require("./auth/capability-discovery.js");
|
|
89
95
|
var _discoveryfetchts = require("./auth/discovery-fetch.js");
|
|
90
96
|
var _interactiveoauthflowts = require("./auth/interactive-oauth-flow.js");
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.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":["DcrAuthenticator","DiscoveryFetchError","DynamicClientRegistrar","InteractiveOAuthFlow","OAuthCallbackListener","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","createServerRegistry","decorateClient","getLogLevel","isLoopbackUrl","logger","probeAuthCapabilities","resolveArgsPaths","resolvePath","search","searchCapabilities","setLogLevel","validateServers"],"mappings":"AAAA;;CAEC
|
|
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\nexport type { VersionNegotiationOptions } from '@modelcontextprotocol/client';\n// SDK re-exports for protocol version negotiation: the connect-option type and the typed\n// errors a negotiation can fail with, so callers can handle era mismatch without\n// depending on the SDK themselves.\nexport { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';\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 { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.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":["DcrAuthenticator","DiscoveryFetchError","DynamicClientRegistrar","InteractiveOAuthFlow","OAuthCallbackListener","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","SdkError","SdkErrorCode","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","createServerRegistry","decorateClient","getLogLevel","isLoopbackUrl","logger","probeAuthCapabilities","resolveArgsPaths","resolvePath","search","searchCapabilities","setLogLevel","validateServers"],"mappings":"AAAA;;CAEC;;;;;;;;;;;QAsBQA;eAAAA,oCAAgB;;QAXhBC;eAAAA,qCAAmB;;QAYnBC;eAAAA,gDAAsB;;QAVtBC;eAAAA,4CAAoB;;QACpBC;eAAAA,8CAAqB;;QAgB5BC;eAAAA,uCAAmB;;QACnBC;eAAAA,yCAAqB;;QACrBC;eAAAA,yCAAqB;;QACrBC;eAAAA,2CAAuB;;QA3BhBC;eAAAA,gBAAQ;;QAAEC;eAAAA,oBAAY;;QA4B7BC;eAAAA,qCAAiB;;QACjBC;eAAAA,uCAAmB;;QAIZC;eAAAA,6BAAoB;;QAEgCC;eAAAA,oCAAoB;;QAzBxEC;eAAAA,+BAAc;;QA4BdC;eAAAA,qBAAW;;QAjCUC;eAAAA,+BAAa;;QAiCOC;eAAAA,gBAAM;;QAlC/CC;eAAAA,4CAAqB;;QAmCrBC;eAAAA,6BAAgB;;QAAEC;eAAAA,wBAAW;;QANPC;eAAAA,eAAM;;QAAEC;eAAAA,2BAAkB;;QAKCC;eAAAA,qBAAW;;QA1BrCC;eAAAA,iCAAe;;;sBAZR;qCAID;gCACa;sCAEd;uCACC;+BAE4H;gCAE3G;kCAItB;wCACM;kCAahC;uBAG0D;8BAE+E;wBAGnE;2BAC/B"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Helper to connect MCP SDK clients to servers with intelligent transport inference.
|
|
5
5
|
* Automatically detects transport type from URL protocol or type field.
|
|
6
6
|
*/
|
|
7
|
+
import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
7
8
|
import { Client } from '@modelcontextprotocol/client';
|
|
8
9
|
import { type DcrAuthenticatorOptions } from '../dcr/index.js';
|
|
9
10
|
import type { ServerProcess } from '../spawn/spawn-server.js';
|
|
@@ -32,6 +33,15 @@ import { type Logger } from '../utils/logger.js';
|
|
|
32
33
|
*
|
|
33
34
|
* @param registryOrConfig - Result from createServerRegistry() or servers config object
|
|
34
35
|
* @param serverName - Server name from servers config
|
|
36
|
+
* @param options - Connection options (see below)
|
|
37
|
+
* @param options.dcrAuthenticator - DCR authenticator options
|
|
38
|
+
* @param options.logger - Logger for connection diagnostics
|
|
39
|
+
* @param options.versionNegotiation - SDK protocol version negotiation (protocol revision
|
|
40
|
+
* 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:
|
|
41
|
+
* the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and
|
|
42
|
+
* fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`
|
|
43
|
+
* to require the pinned revision (a server that cannot serve it fails the connect with
|
|
44
|
+
* a typed era-negotiation error).
|
|
35
45
|
* @returns Connected MCP SDK Client (guaranteed ready)
|
|
36
46
|
*
|
|
37
47
|
* @example
|
|
@@ -54,5 +64,6 @@ import { type Logger } from '../utils/logger.js';
|
|
|
54
64
|
export declare function connectMcpClient(registryOrConfig: RegistryLike | ServersConfig, serverName: string, options?: {
|
|
55
65
|
dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
|
|
56
66
|
logger?: Logger;
|
|
67
|
+
versionNegotiation?: VersionNegotiationOptions;
|
|
57
68
|
}): Promise<Client>;
|
|
58
69
|
export {};
|
|
@@ -83,6 +83,15 @@ import { waitForHttpReady } from './wait-for-http-ready.js';
|
|
|
83
83
|
*
|
|
84
84
|
* @param registryOrConfig - Result from createServerRegistry() or servers config object
|
|
85
85
|
* @param serverName - Server name from servers config
|
|
86
|
+
* @param options - Connection options (see below)
|
|
87
|
+
* @param options.dcrAuthenticator - DCR authenticator options
|
|
88
|
+
* @param options.logger - Logger for connection diagnostics
|
|
89
|
+
* @param options.versionNegotiation - SDK protocol version negotiation (protocol revision
|
|
90
|
+
* 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:
|
|
91
|
+
* the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and
|
|
92
|
+
* fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`
|
|
93
|
+
* to require the pinned revision (a server that cannot serve it fails the connect with
|
|
94
|
+
* a typed era-negotiation error).
|
|
86
95
|
* @returns Connected MCP SDK Client (guaranteed ready)
|
|
87
96
|
*
|
|
88
97
|
* @example
|
|
@@ -115,13 +124,20 @@ import { waitForHttpReady } from './wait-for-http-ready.js';
|
|
|
115
124
|
}
|
|
116
125
|
// Infer transport type with validation
|
|
117
126
|
const transportType = inferTransportType(serverConfig);
|
|
127
|
+
// SDK client options for both transports (main + SSE fallback). versionNegotiation is
|
|
128
|
+
// omitted rather than set to undefined so the default stays the SDK's 'legacy' mode —
|
|
129
|
+
// the plain 2025 connect sequence — for callers that do not pass it.
|
|
130
|
+
const clientOptions = {
|
|
131
|
+
capabilities: {}
|
|
132
|
+
};
|
|
133
|
+
if ((options === null || options === void 0 ? void 0 : options.versionNegotiation) !== undefined) {
|
|
134
|
+
clientOptions.versionNegotiation = options.versionNegotiation;
|
|
135
|
+
}
|
|
118
136
|
// Create MCP client
|
|
119
137
|
const client = new Client({
|
|
120
138
|
name: 'mcp-cli-client',
|
|
121
139
|
version: '1.0.0'
|
|
122
|
-
},
|
|
123
|
-
capabilities: {}
|
|
124
|
-
});
|
|
140
|
+
}, clientOptions);
|
|
125
141
|
// Connect based on inferred transport
|
|
126
142
|
if (transportType === 'stdio') {
|
|
127
143
|
// Check if we have a spawned process in the registry
|
|
@@ -232,9 +248,7 @@ import { waitForHttpReady } from './wait-for-http-ready.js';
|
|
|
232
248
|
const sseClient = new Client({
|
|
233
249
|
name: 'mcp-cli-client',
|
|
234
250
|
version: '1.0.0'
|
|
235
|
-
},
|
|
236
|
-
capabilities: {}
|
|
237
|
-
});
|
|
251
|
+
}, clientOptions);
|
|
238
252
|
// SSE transport with merged headers (static + DCR auth)
|
|
239
253
|
// Reuse the same header merging logic as Streamable HTTP
|
|
240
254
|
const staticHeaders = serverConfig.headers || {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport type { Transport } from '@modelcontextprotocol/client';\nimport { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { StdioClientTransport } from '@modelcontextprotocol/client/stdio';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport { normalizeUrl } from '../lib/url-utils.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n // The canonical MCP server URI, path segment and all. Both calls below need\n // the server's identity, not its deployment root: discovery uses the path to\n // find resource-specific metadata (RFC 9728 sub-path), and the authenticator\n // audience-binds tokens to it (RFC 8707). Handing either the `/mcp`-stripped\n // base names a different resource, which authorization servers that validate\n // the `resource` indicator reject as `invalid_target`.\n const mcpServerUrl = normalizeUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(mcpServerUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(mcpServerUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["Client","SSEClientTransport","StreamableHTTPClientTransport","StdioClientTransport","getPort","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","DcrAuthenticator","normalizeUrl","logger","defaultLogger","ExistingProcessTransport","waitForHttpReady","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","inferTransportType","config","type","url","URL","protocol","connectMcpClient","registryOrConfig","serverName","options","isRegistry","servers","Map","serversConfig","registry","undefined","serverConfig","available","Object","keys","join","transportType","client","name","version","capabilities","serverHandle","get","transport","process","connect","command","args","env","isSpawnedHttp","has","debug","mcpServerUrl","authToken","supportsDcr","port","redirectUri","authenticator","headless","dcrAuthenticator","tokens","ensureAuthenticated","accessToken","staticHeaders","headers","dcrHeaders","Authorization","mergedHeaders","transportOptions","length","requestInit","error","errorMessage","message","String","cause","isConnectionRefused","code","includes","close","catch","shouldFallback","warn","sseClient","sseTransportOptions","sseTransport","sseError","all"],"mappings":"AAAA;;;;;CAKC,GAGD,SAASA,MAAM,EAAEC,kBAAkB,EAAEC,6BAA6B,QAAQ,+BAA+B;AACzG,SAASC,oBAAoB,QAAQ,qCAAqC;AAC1E,OAAOC,aAAa,WAAW;AAC/B,SAASC,qBAAqB,QAAQ,mBAAmB;AACzD,SAASC,+BAA+B,QAAQ,kBAAkB;AAClE,SAASC,gBAAgB,QAAsC,kBAAkB;AACjF,SAASC,YAAY,QAAQ,sBAAsB;AAcnD,SAASC,UAAUC,aAAa,QAAqB,qBAAqB;AAC1E,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,gBAAgB,QAAQ,2BAA2B;AAE5D;;;;;;;CAOC,GACD,eAAeC,YAAeC,OAAmB,EAAEC,EAAU,EAAEC,SAAiB;IAC9E,IAAIC;IAEJ,OAAOC,QAAQC,IAAI,CAAC;QAClBL,QAAQM,OAAO,CAAC,IAAMC,aAAaJ;QACnC,IAAIC,QAAW,CAACI,GAAGC;YACjBN,YAAYO,WAAW,IAAMD,OAAO,IAAIE,MAAM,CAAC,cAAc,EAAEV,GAAG,IAAI,EAAEC,WAAW,IAAID;QACzF;KACD;AACH;AAEA;;;;;;;;;;;CAWC,GACD,SAASW,mBAAmBC,MAAsB;IAChD,kCAAkC;IAClC,IAAIA,OAAOC,IAAI,EAAE;QACf,gDAAgD;QAChD,IAAID,OAAOE,GAAG,EAAE;YACd,MAAMA,MAAM,IAAIC,IAAIH,OAAOE,GAAG;YAC9B,MAAME,WAAWF,IAAIE,QAAQ;YAE7B,IAAI,AAACA,CAAAA,aAAa,WAAWA,aAAa,QAAO,KAAMJ,OAAOC,IAAI,KAAK,UAAUD,OAAOC,IAAI,KAAK,WAAW;gBAC1G,MAAM,IAAIH,MAAM,CAAC,qCAAqC,EAAEM,SAAS,iCAAiC,EAAEJ,OAAOC,IAAI,CAAC,CAAC,CAAC;YACpH;QACF;QAEA,yBAAyB;QACzB,IAAID,OAAOC,IAAI,KAAK,UAAUD,OAAOC,IAAI,KAAK,WAAW,OAAO;QAChE,IAAID,OAAOC,IAAI,KAAK,SAAS,OAAO;QAEpC,MAAM,IAAIH,MAAM,CAAC,4BAA4B,EAAEE,OAAOC,IAAI,EAAE;IAC9D;IAEA,sCAAsC;IACtC,IAAID,OAAOE,GAAG,EAAE;QACd,MAAMA,MAAM,IAAIC,IAAIH,OAAOE,GAAG;QAC9B,MAAME,WAAWF,IAAIE,QAAQ;QAE7B,IAAIA,aAAa,WAAWA,aAAa,UAAU;YACjD,OAAO;QACT;QACA,MAAM,IAAIN,MAAM,CAAC,0BAA0B,EAAEM,UAAU;IACzD;IAEA,+BAA+B;IAC/B,OAAO;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GACD,OAAO,eAAeC,iBACpBC,gBAA8C,EAC9CC,UAAkB,EAClBC,OAGC;;IAED,gEAAgE;IAChE,MAAMC,aAAa,aAAaH,oBAAoBA,iBAAiBI,OAAO,YAAYC;IACxF,MAAMC,gBAA+BH,aAAa,AAACH,iBAAkCN,MAAM,GAAIM;IAC/F,MAAMO,WAAWJ,aAAcH,mBAAoCQ;IACnE,MAAMhC,iBAAS0B,oBAAAA,8BAAAA,QAAS1B,MAAM,uCAAIC;IAElC,MAAMgC,eAAeH,aAAa,CAACL,WAAW;IAE9C,IAAI,CAACQ,cAAc;QACjB,MAAMC,YAAYC,OAAOC,IAAI,CAACN,eAAeO,IAAI,CAAC;QAClD,MAAM,IAAIrB,MAAM,CAAC,QAAQ,EAAES,WAAW,0CAA0C,EAAES,aAAa,QAAQ;IACzG;IAEA,uCAAuC;IACvC,MAAMI,gBAAgBrB,mBAAmBgB;IAEzC,oBAAoB;IACpB,MAAMM,SAAS,IAAIhD,OAAO;QAAEiD,MAAM;QAAkBC,SAAS;IAAQ,GAAG;QAAEC,cAAc,CAAC;IAAE;IAE3F,sCAAsC;IACtC,IAAIJ,kBAAkB,SAAS;QAC7B,qDAAqD;QACrD,MAAMK,eAAeZ,qBAAAA,+BAAAA,SAAUH,OAAO,CAACgB,GAAG,CAACnB;QAE3C,IAAIkB,cAAc;YAChB,oCAAoC;YACpC,MAAME,YAAY,IAAI3C,yBAAyByC,aAAaG,OAAO;YACnE,MAAMP,OAAOQ,OAAO,CAACF;QACvB,OAAO;YACL,qEAAqE;YACrE,oEAAoE;YACpE,IAAI,CAACZ,aAAae,OAAO,EAAE;gBACzB,MAAM,IAAIhC,MAAM,CAAC,QAAQ,EAAES,WAAW,iDAAiD,CAAC;YAC1F;YAEA,MAAMoB,YAAY,IAAInD,qBAAqB;gBACzCsD,SAASf,aAAae,OAAO;gBAC7BC,MAAMhB,aAAagB,IAAI,IAAI,EAAE;gBAC7BC,KAAKjB,aAAaiB,GAAG,IAAI,CAAC;YAC5B;YAEA,qFAAqF;YACrF,MAAMX,OAAOQ,OAAO,CAACF;QACvB;IACF,OAAO,IAAIP,kBAAkB,QAAQ;QACnC,IAAI,CAAE,CAAA,SAASL,YAAW,KAAM,CAACA,aAAab,GAAG,EAAE;YACjD,MAAM,IAAIJ,MAAM,CAAC,QAAQ,EAAES,WAAW,4CAA4C,CAAC;QACrF;QAEA,iEAAiE;QACjE,iEAAiE;QACjE,MAAM0B,gBAAgBpB,qBAAAA,+BAAAA,SAAUH,OAAO,CAACwB,GAAG,CAAC3B;QAE5C,IAAI0B,eAAe;YACjBnD,OAAOqD,KAAK,CAAC,CAAC,4CAA4C,EAAE5B,WAAW,KAAK,EAAEQ,aAAab,GAAG,EAAE;YAChG,MAAMjB,iBAAiB8B,aAAab,GAAG;YACvCpB,OAAOqD,KAAK,CAAC,CAAC,gCAAgC,EAAE5B,WAAW,OAAO,CAAC;QACrE;QAEA,MAAML,MAAM,IAAIC,IAAIY,aAAab,GAAG;QAEpC,gEAAgE;QAChE,4EAA4E;QAC5E,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,uDAAuD;QACvD,MAAMkC,eAAevD,aAAakC,aAAab,GAAG;QAClD,MAAMsB,eAAe,MAAMtC,YAAYR,sBAAsB0D,eAAezD,iCAAiC;QAE7G,IAAI0D;QAEJ,IAAIb,aAAac,WAAW,EAAE;YAC5BxD,OAAOqD,KAAK,CAAC,CAAC,WAAW,EAAE5B,WAAW,6BAA6B,CAAC;YAEpE,8DAA8D;YAC9D,MAAMgC,OAAO,MAAM9D;YACnB,MAAM+D,cAAc,CAAC,iBAAiB,EAAED,KAAK,SAAS,CAAC;YAEvD,+EAA+E;YAC/E,MAAME,gBAAgB,IAAI7D,iBAAiB;gBACzC8D,UAAU;gBACVF;gBACA1D;mBACG0B,oBAAAA,8BAAAA,QAASmC,gBAAgB,AAA5B;YACF;YAEA,+DAA+D;YAC/D,MAAMC,SAAS,MAAMH,cAAcI,mBAAmB,CAACT,cAAcZ;YACrEa,YAAYO,OAAOE,WAAW;YAE9BhE,OAAOqD,KAAK,CAAC,CAAC,+BAA+B,EAAE5B,WAAW,CAAC,CAAC;QAC9D,OAAO;YACLzB,OAAOqD,KAAK,CAAC,CAAC,YAAY,EAAE5B,WAAW,0DAA0D,CAAC;QACpG;QAEA,IAAI;YACF,iEAAiE;YACjE,8FAA8F;YAC9F,MAAMwC,gBAAgBhC,aAAaiC,OAAO,IAAI,CAAC;YAC/C,MAAMC,aAAaZ,YAAY;gBAAEa,eAAe,CAAC,OAAO,EAAEb,WAAW;YAAC,IAAI,CAAC;YAC3E,MAAMc,gBAAgB;gBAAE,GAAGJ,aAAa;gBAAE,GAAGE,UAAU;YAAC;YAExD,MAAMG,mBACJnC,OAAOC,IAAI,CAACiC,eAAeE,MAAM,GAAG,IAChC;gBACEC,aAAa;oBACXN,SAASG;gBACX;YACF,IACArC;YAEN,MAAMa,YAAY,IAAIpD,8BAA8B2B,KAAKkD;YACzD,+FAA+F;YAC/F,gEAAgE;YAChE,MAAMlE,YAAYmC,OAAOQ,OAAO,CAACF,YAAoC,OAAO;QAC9E,EAAE,OAAO4B,OAAO;YACd,+DAA+D;YAC/D,iFAAiF;YACjF,MAAMC,eAAeD,iBAAiBzD,QAAQyD,MAAME,OAAO,GAAGC,OAAOH;YAErE,0EAA0E;YAC1E,wFAAwF;YACxF,MAAMI,QAAQJ,iBAAiBzD,QAAQ,AAACyD,MAAgDI,KAAK,GAAG7C;YAChG,MAAM8C,sBAAsBD,CAAAA,kBAAAA,4BAAAA,MAAOE,IAAI,MAAK,kBAAkBL,aAAaM,QAAQ,CAAC;YAEpF,IAAIF,qBAAqB;gBACvB,4CAA4C;gBAC5C,MAAMvC,OAAO0C,KAAK,GAAGC,KAAK,CAAC,KAAO;gBAClC,MAAM,IAAIlE,MAAM,CAAC,sBAAsB,EAAEI,KAAK;YAChD;YAEA,8DAA8D;YAC9D,MAAM+D,iBACJT,aAAaM,QAAQ,CAAC,yBAAyB,mBAAmB;YAClEN,aAAaM,QAAQ,CAAC,UAAU,+CAA+C;YAC/EN,aAAaM,QAAQ,CAAC,QAAQ,qBAAqB;YAErD,IAAIG,gBAAgB;gBAClBnF,OAAOoF,IAAI,CAAC,CAAC,wBAAwB,EAAEV,aAAa,gCAAgC,CAAC;YACvF,OAAO;gBACL1E,OAAOoF,IAAI,CAAC;YACd;YAEA,iEAAiE;YACjE,MAAMC,YAAY,IAAI9F,OAAO;gBAAEiD,MAAM;gBAAkBC,SAAS;YAAQ,GAAG;gBAAEC,cAAc,CAAC;YAAE;YAE9F,wDAAwD;YACxD,yDAAyD;YACzD,MAAMuB,gBAAgBhC,aAAaiC,OAAO,IAAI,CAAC;YAC/C,MAAMC,aAAaZ,YAAY;gBAAEa,eAAe,CAAC,OAAO,EAAEb,WAAW;YAAC,IAAI,CAAC;YAC3E,MAAMc,gBAAgB;gBAAE,GAAGJ,aAAa;gBAAE,GAAGE,UAAU;YAAC;YAExD,MAAMmB,sBACJnD,OAAOC,IAAI,CAACiC,eAAeE,MAAM,GAAG,IAChC;gBACEC,aAAa;oBACXN,SAASG;gBACX;YACF,IACArC;YAEN,MAAMuD,eAAe,IAAI/F,mBAAmB4B,KAAKkE;YAEjD,IAAI;gBACF,MAAMlF,YAAYiF,UAAUtC,OAAO,CAACwC,eAAe,OAAO;gBAC1D,wCAAwC;gBACxC,OAAOF;YACT,EAAE,OAAOG,UAAU;gBACjB,gEAAgE;gBAChE,MAAM/E,QAAQgF,GAAG,CAAC;oBAAClD,OAAO0C,KAAK,GAAGC,KAAK,CAAC,KAAO;oBAAIG,UAAUJ,KAAK,GAAGC,KAAK,CAAC,KAAO;iBAAG;gBACrF,MAAMM;YACR;QACF;IACF;IAEA,OAAOjD,QAAQ,iCAAiC;AAClD"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport type { ClientOptions, Transport, VersionNegotiationOptions } from '@modelcontextprotocol/client';\nimport { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { StdioClientTransport } from '@modelcontextprotocol/client/stdio';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport { normalizeUrl } from '../lib/url-utils.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @param options - Connection options (see below)\n * @param options.dcrAuthenticator - DCR authenticator options\n * @param options.logger - Logger for connection diagnostics\n * @param options.versionNegotiation - SDK protocol version negotiation (protocol revision\n * 2026-07-28 and later). Omitted by default, which keeps the SDK's `'legacy'` mode:\n * the plain 2025 connect sequence. Pass `{ mode: 'auto' }` to probe the server and\n * fall back to 2025 when it cannot serve the modern era, or `{ mode: { pin: '2026-07-28' } }`\n * to require the pinned revision (a server that cannot serve it fails the connect with\n * a typed era-negotiation error).\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n versionNegotiation?: VersionNegotiationOptions;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // SDK client options for both transports (main + SSE fallback). versionNegotiation is\n // omitted rather than set to undefined so the default stays the SDK's 'legacy' mode —\n // the plain 2025 connect sequence — for callers that do not pass it.\n const clientOptions: ClientOptions = { capabilities: {} };\n if (options?.versionNegotiation !== undefined) {\n clientOptions.versionNegotiation = options.versionNegotiation;\n }\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, clientOptions);\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n // The canonical MCP server URI, path segment and all. Both calls below need\n // the server's identity, not its deployment root: discovery uses the path to\n // find resource-specific metadata (RFC 9728 sub-path), and the authenticator\n // audience-binds tokens to it (RFC 8707). Handing either the `/mcp`-stripped\n // base names a different resource, which authorization servers that validate\n // the `resource` indicator reject as `invalid_target`.\n const mcpServerUrl = normalizeUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(mcpServerUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(mcpServerUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, clientOptions);\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["Client","SSEClientTransport","StreamableHTTPClientTransport","StdioClientTransport","getPort","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","DcrAuthenticator","normalizeUrl","logger","defaultLogger","ExistingProcessTransport","waitForHttpReady","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","inferTransportType","config","type","url","URL","protocol","connectMcpClient","registryOrConfig","serverName","options","isRegistry","servers","Map","serversConfig","registry","undefined","serverConfig","available","Object","keys","join","transportType","clientOptions","capabilities","versionNegotiation","client","name","version","serverHandle","get","transport","process","connect","command","args","env","isSpawnedHttp","has","debug","mcpServerUrl","authToken","supportsDcr","port","redirectUri","authenticator","headless","dcrAuthenticator","tokens","ensureAuthenticated","accessToken","staticHeaders","headers","dcrHeaders","Authorization","mergedHeaders","transportOptions","length","requestInit","error","errorMessage","message","String","cause","isConnectionRefused","code","includes","close","catch","shouldFallback","warn","sseClient","sseTransportOptions","sseTransport","sseError","all"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @mcp-z/client - MCP Client Library
|
|
3
3
|
*/
|
|
4
|
+
export type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
|
|
5
|
+
export { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';
|
|
4
6
|
export type { McpServerEntry, StartConfig } from '../schemas/servers.d.js';
|
|
5
7
|
export { probeAuthCapabilities } from './auth/capability-discovery.js';
|
|
6
8
|
export { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @mcp-z/client - MCP Client Library
|
|
3
|
-
*/ //
|
|
3
|
+
*/ // SDK re-exports for protocol version negotiation: the connect-option type and the typed
|
|
4
|
+
// errors a negotiation can fail with, so callers can handle era mismatch without
|
|
5
|
+
// depending on the SDK themselves.
|
|
6
|
+
export { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';
|
|
4
7
|
// Auth - OAuth utilities
|
|
5
8
|
export { probeAuthCapabilities } from './auth/capability-discovery.js';
|
|
6
9
|
export { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.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","DiscoveryFetchError","isLoopbackUrl","InteractiveOAuthFlow","OAuthCallbackListener","decorateClient","validateServers","DcrAuthenticator","DynamicClientRegistrar","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","search","searchCapabilities","createServerRegistry","getLogLevel","logger","setLogLevel","resolveArgsPaths","resolvePath"],"mappings":"AAAA;;CAEC,
|
|
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\nexport type { VersionNegotiationOptions } from '@modelcontextprotocol/client';\n// SDK re-exports for protocol version negotiation: the connect-option type and the typed\n// errors a negotiation can fail with, so callers can handle era mismatch without\n// depending on the SDK themselves.\nexport { SdkError, SdkErrorCode } from '@modelcontextprotocol/client';\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 { DiscoveryFetchError, isLoopbackUrl } from './auth/discovery-fetch.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":["SdkError","SdkErrorCode","probeAuthCapabilities","DiscoveryFetchError","isLoopbackUrl","InteractiveOAuthFlow","OAuthCallbackListener","decorateClient","validateServers","DcrAuthenticator","DynamicClientRegistrar","PromptResponseError","PromptResponseWrapper","ResourceResponseError","ResourceResponseWrapper","ToolResponseError","ToolResponseWrapper","buildCapabilityIndex","search","searchCapabilities","createServerRegistry","getLogLevel","logger","setLogLevel","resolveArgsPaths","resolvePath"],"mappings":"AAAA;;CAEC,GAGD,yFAAyF;AACzF,iFAAiF;AACjF,mCAAmC;AACnC,SAASA,QAAQ,EAAEC,YAAY,QAAQ,+BAA+B;AAGtE,yBAAyB;AACzB,SAASC,qBAAqB,QAAQ,iCAAiC;AACvE,SAASC,mBAAmB,EAAEC,aAAa,QAAQ,4BAA4B;AAE/E,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"}
|