@mcp-z/client 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,6 +1,15 @@
1
1
  export declare class DiscoveryFetchError extends Error {
2
2
  constructor(message: string);
3
3
  }
4
+ type LookupRecord = {
5
+ address: string;
6
+ family: number;
7
+ };
8
+ /** DNS implementation, injectable for deterministic tests. Same contract as `dns.lookup` with `{ all: true, verbatim: true }`. */
9
+ type Lookup = (hostname: string, options: {
10
+ all: true;
11
+ verbatim: true;
12
+ }, callback: (error: NodeJS.ErrnoException | null, addresses: LookupRecord[]) => void) => void;
4
13
  /**
5
14
  * True if `rawUrl`'s host is loopback, used to decide `allowLoopback` grants
6
15
  * from the URL the caller configured, not remote-supplied data. Fails closed on an unparseable URL.
@@ -13,15 +22,25 @@ export interface DiscoveryFetchOptions {
13
22
  */
14
23
  allowLoopback?: boolean;
15
24
  /**
16
- * Per-request connect/read timeout in ms. Defaults to `DEFAULT_TIMEOUT_MS`;
17
- * overridable so tests can bound slow-failure cases.
25
+ * Per-hop timeout in ms, applied to both the DNS resolution and the request.
26
+ * Defaults to `DEFAULT_TIMEOUT_MS`; overridable so tests can bound slow-failure cases.
18
27
  */
19
28
  timeoutMs?: number;
29
+ /**
30
+ * DNS implementation used for the pre-request resolution, injectable for
31
+ * deterministic tests. Defaults to `dns.lookup`.
32
+ */
33
+ lookup?: Lookup;
20
34
  }
21
35
  /**
22
36
  * Fetches an OAuth-discovery URL with SSRF mitigations applied to the
23
37
  * initial URL and every redirect hop; redirects are validated, not auto-followed.
24
38
  *
39
+ * The hostname is resolved once, every returned address is validated, and the
40
+ * validated set is pinned into the request through a custom `lookup`, so the
41
+ * request cannot resolve the hostname a second time and cannot be steered to
42
+ * a different address by a DNS-rebinding answer.
43
+ *
25
44
  * @param rawUrl - URL to fetch; may be remote-server-supplied (the threat this guards against).
26
45
  * @param init - Standard fetch options; `redirect` is always forced to `'manual'`.
27
46
  * @param context - Short label used only in error messages, never echoing the URL.
@@ -33,3 +52,4 @@ export declare function discoveryFetch(rawUrl: string, init?: RequestInit, conte
33
52
  * while reading (not after buffering the whole thing).
34
53
  */
35
54
  export declare function readDiscoveryJson<T>(response: Response, context: string): Promise<T>;
55
+ export {};
@@ -1,6 +1,15 @@
1
1
  export declare class DiscoveryFetchError extends Error {
2
2
  constructor(message: string);
3
3
  }
4
+ type LookupRecord = {
5
+ address: string;
6
+ family: number;
7
+ };
8
+ /** DNS implementation, injectable for deterministic tests. Same contract as `dns.lookup` with `{ all: true, verbatim: true }`. */
9
+ type Lookup = (hostname: string, options: {
10
+ all: true;
11
+ verbatim: true;
12
+ }, callback: (error: NodeJS.ErrnoException | null, addresses: LookupRecord[]) => void) => void;
4
13
  /**
5
14
  * True if `rawUrl`'s host is loopback, used to decide `allowLoopback` grants
6
15
  * from the URL the caller configured, not remote-supplied data. Fails closed on an unparseable URL.
@@ -13,15 +22,25 @@ export interface DiscoveryFetchOptions {
13
22
  */
14
23
  allowLoopback?: boolean;
15
24
  /**
16
- * Per-request connect/read timeout in ms. Defaults to `DEFAULT_TIMEOUT_MS`;
17
- * overridable so tests can bound slow-failure cases.
25
+ * Per-hop timeout in ms, applied to both the DNS resolution and the request.
26
+ * Defaults to `DEFAULT_TIMEOUT_MS`; overridable so tests can bound slow-failure cases.
18
27
  */
19
28
  timeoutMs?: number;
29
+ /**
30
+ * DNS implementation used for the pre-request resolution, injectable for
31
+ * deterministic tests. Defaults to `dns.lookup`.
32
+ */
33
+ lookup?: Lookup;
20
34
  }
21
35
  /**
22
36
  * Fetches an OAuth-discovery URL with SSRF mitigations applied to the
23
37
  * initial URL and every redirect hop; redirects are validated, not auto-followed.
24
38
  *
39
+ * The hostname is resolved once, every returned address is validated, and the
40
+ * validated set is pinned into the request through a custom `lookup`, so the
41
+ * request cannot resolve the hostname a second time and cannot be steered to
42
+ * a different address by a DNS-rebinding answer.
43
+ *
25
44
  * @param rawUrl - URL to fetch; may be remote-server-supplied (the threat this guards against).
26
45
  * @param init - Standard fetch options; `redirect` is always forced to `'manual'`.
27
46
  * @param context - Short label used only in error messages, never echoing the URL.
@@ -33,3 +52,4 @@ export declare function discoveryFetch(rawUrl: string, init?: RequestInit, conte
33
52
  * while reading (not after buffering the whole thing).
34
53
  */
35
54
  export declare function readDiscoveryJson<T>(response: Response, context: string): Promise<T>;
55
+ export {};