@adcp/sdk 12.0.3 → 12.0.4

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.
@@ -37,4 +37,5 @@
37
37
  * - Type-safe tool methods
38
38
  * - Error handling and validation
39
39
  */
40
- export { ProtocolClient, callMCPTool, callA2ATool, createMCPClient, createA2AClient } from './protocols/index.mjs';
40
+ export { ProtocolClient, callMCPTool, callMCPToolWithOAuth, connectMCP, callA2ATool, createMCPClient, createA2AClient, } from './protocols/index.mjs';
41
+ export type { MCPCallOptions, MCPConnectionResult } from './protocols/index.mjs';
@@ -37,5 +37,6 @@
37
37
  * - Type-safe tool methods
38
38
  * - Error handling and validation
39
39
  */
40
- export { ProtocolClient, callMCPTool, callA2ATool, createMCPClient, createA2AClient } from './protocols';
40
+ export { ProtocolClient, callMCPTool, callMCPToolWithOAuth, connectMCP, callA2ATool, createMCPClient, createA2AClient, } from './protocols';
41
+ export type { MCPCallOptions, MCPConnectionResult } from './protocols';
41
42
  //# sourceMappingURL=advanced.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../../src/lib/advanced.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../../src/lib/advanced.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,WAAW,EACX,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -21,6 +21,8 @@ __export(advanced_exports, {
21
21
  ProtocolClient: () => import_protocols.ProtocolClient,
22
22
  callA2ATool: () => import_protocols.callA2ATool,
23
23
  callMCPTool: () => import_protocols.callMCPTool,
24
+ callMCPToolWithOAuth: () => import_protocols.callMCPToolWithOAuth,
25
+ connectMCP: () => import_protocols.connectMCP,
24
26
  createA2AClient: () => import_protocols.createA2AClient,
25
27
  createMCPClient: () => import_protocols.createMCPClient
26
28
  });
@@ -31,6 +33,8 @@ var import_protocols = require('./protocols/index.js');
31
33
  ProtocolClient,
32
34
  callA2ATool,
33
35
  callMCPTool,
36
+ callMCPToolWithOAuth,
37
+ connectMCP,
34
38
  createA2AClient,
35
39
  createMCPClient
36
40
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/advanced.ts"],"sourcesContent":["/**\n * Advanced exports for library authors building custom protocol implementations\n *\n * @remarks\n * **Most developers should use AdCPClient from the main export**, which provides:\n * - Single-agent access via `client.agent(id)` with conversation context\n * - Multi-agent parallel operations via `client.agents([ids])`\n * - All AdCP tools with full type safety\n *\n * These low-level protocol clients are only needed if you're:\n * - Building custom protocol handlers\n * - Integrating AdCP with other frameworks\n * - Implementing custom agent orchestration\n *\n * @example\n * ```typescript\n * // ❌ Don't do this - use main AdCPClient instead:\n * import { callA2ATool } from '@adcp/sdk/advanced';\n *\n * // ✅ Do this - use the main client:\n * import { AdCPClient } from '@adcp/sdk';\n * const client = new AdCPClient([agentConfig]);\n * const agent = client.agent('agent-id');\n * await agent.getProducts({ brief: '...' });\n * ```\n */\n\n/**\n * Protocol-level clients for direct protocol interaction\n *\n * @remarks\n * Low-level clients for MCP and A2A protocols. Used internally by AdCPClient.\n * Only use these if you need to build custom protocol handlers or integrations.\n *\n * For normal usage, prefer AdCPClient which wraps these and provides:\n * - Automatic agent configuration\n * - Conversation context management\n * - Type-safe tool methods\n * - Error handling and validation\n */\nexport { ProtocolClient, callMCPTool, callA2ATool, createMCPClient, createA2AClient } from './protocols';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwCA,uBAA2F;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/advanced.ts"],"sourcesContent":["/**\n * Advanced exports for library authors building custom protocol implementations\n *\n * @remarks\n * **Most developers should use AdCPClient from the main export**, which provides:\n * - Single-agent access via `client.agent(id)` with conversation context\n * - Multi-agent parallel operations via `client.agents([ids])`\n * - All AdCP tools with full type safety\n *\n * These low-level protocol clients are only needed if you're:\n * - Building custom protocol handlers\n * - Integrating AdCP with other frameworks\n * - Implementing custom agent orchestration\n *\n * @example\n * ```typescript\n * // ❌ Don't do this - use main AdCPClient instead:\n * import { callA2ATool } from '@adcp/sdk/advanced';\n *\n * // ✅ Do this - use the main client:\n * import { AdCPClient } from '@adcp/sdk';\n * const client = new AdCPClient([agentConfig]);\n * const agent = client.agent('agent-id');\n * await agent.getProducts({ brief: '...' });\n * ```\n */\n\n/**\n * Protocol-level clients for direct protocol interaction\n *\n * @remarks\n * Low-level clients for MCP and A2A protocols. Used internally by AdCPClient.\n * Only use these if you need to build custom protocol handlers or integrations.\n *\n * For normal usage, prefer AdCPClient which wraps these and provides:\n * - Automatic agent configuration\n * - Conversation context management\n * - Type-safe tool methods\n * - Error handling and validation\n */\nexport {\n ProtocolClient,\n callMCPTool,\n callMCPToolWithOAuth,\n connectMCP,\n callA2ATool,\n createMCPClient,\n createA2AClient,\n} from './protocols';\nexport type { MCPCallOptions, MCPConnectionResult } from './protocols';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwCA,uBAQO;","names":[]}
@@ -1,8 +1,18 @@
1
- import { ProtocolClient, callMCPTool, callA2ATool, createMCPClient, createA2AClient } from "./protocols/index.mjs";
1
+ import {
2
+ ProtocolClient,
3
+ callMCPTool,
4
+ callMCPToolWithOAuth,
5
+ connectMCP,
6
+ callA2ATool,
7
+ createMCPClient,
8
+ createA2AClient
9
+ } from "./protocols/index.mjs";
2
10
  export {
3
11
  ProtocolClient,
4
12
  callA2ATool,
5
13
  callMCPTool,
14
+ callMCPToolWithOAuth,
15
+ connectMCP,
6
16
  createA2AClient,
7
17
  createMCPClient
8
18
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/advanced.ts"],"sourcesContent":["/**\n * Advanced exports for library authors building custom protocol implementations\n *\n * @remarks\n * **Most developers should use AdCPClient from the main export**, which provides:\n * - Single-agent access via `client.agent(id)` with conversation context\n * - Multi-agent parallel operations via `client.agents([ids])`\n * - All AdCP tools with full type safety\n *\n * These low-level protocol clients are only needed if you're:\n * - Building custom protocol handlers\n * - Integrating AdCP with other frameworks\n * - Implementing custom agent orchestration\n *\n * @example\n * ```typescript\n * // ❌ Don't do this - use main AdCPClient instead:\n * import { callA2ATool } from '@adcp/sdk/advanced';\n *\n * // ✅ Do this - use the main client:\n * import { AdCPClient } from '@adcp/sdk';\n * const client = new AdCPClient([agentConfig]);\n * const agent = client.agent('agent-id');\n * await agent.getProducts({ brief: '...' });\n * ```\n */\n\n/**\n * Protocol-level clients for direct protocol interaction\n *\n * @remarks\n * Low-level clients for MCP and A2A protocols. Used internally by AdCPClient.\n * Only use these if you need to build custom protocol handlers or integrations.\n *\n * For normal usage, prefer AdCPClient which wraps these and provides:\n * - Automatic agent configuration\n * - Conversation context management\n * - Type-safe tool methods\n * - Error handling and validation\n */\nexport { ProtocolClient, callMCPTool, callA2ATool, createMCPClient, createA2AClient } from './protocols';\n"],"mappings":"AAwCA,SAAS,gBAAgB,aAAa,aAAa,iBAAiB,uBAAuB;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/advanced.ts"],"sourcesContent":["/**\n * Advanced exports for library authors building custom protocol implementations\n *\n * @remarks\n * **Most developers should use AdCPClient from the main export**, which provides:\n * - Single-agent access via `client.agent(id)` with conversation context\n * - Multi-agent parallel operations via `client.agents([ids])`\n * - All AdCP tools with full type safety\n *\n * These low-level protocol clients are only needed if you're:\n * - Building custom protocol handlers\n * - Integrating AdCP with other frameworks\n * - Implementing custom agent orchestration\n *\n * @example\n * ```typescript\n * // ❌ Don't do this - use main AdCPClient instead:\n * import { callA2ATool } from '@adcp/sdk/advanced';\n *\n * // ✅ Do this - use the main client:\n * import { AdCPClient } from '@adcp/sdk';\n * const client = new AdCPClient([agentConfig]);\n * const agent = client.agent('agent-id');\n * await agent.getProducts({ brief: '...' });\n * ```\n */\n\n/**\n * Protocol-level clients for direct protocol interaction\n *\n * @remarks\n * Low-level clients for MCP and A2A protocols. Used internally by AdCPClient.\n * Only use these if you need to build custom protocol handlers or integrations.\n *\n * For normal usage, prefer AdCPClient which wraps these and provides:\n * - Automatic agent configuration\n * - Conversation context management\n * - Type-safe tool methods\n * - Error handling and validation\n */\nexport {\n ProtocolClient,\n callMCPTool,\n callMCPToolWithOAuth,\n connectMCP,\n callA2ATool,\n createMCPClient,\n createA2AClient,\n} from './protocols';\nexport type { MCPCallOptions, MCPConnectionResult } from './protocols';\n"],"mappings":"AAwCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
@@ -34,6 +34,7 @@ export interface ModernMCPConnectionOptions {
34
34
  authProvider?: object;
35
35
  signal?: AbortSignal;
36
36
  requestTimeoutMs?: number;
37
+ fetchFn?: typeof fetch;
37
38
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
38
39
  handleLegacy?: boolean;
39
40
  }
@@ -34,6 +34,7 @@ export interface ModernMCPConnectionOptions {
34
34
  authProvider?: object;
35
35
  signal?: AbortSignal;
36
36
  requestTimeoutMs?: number;
37
+ fetchFn?: typeof fetch;
37
38
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
38
39
  handleLegacy?: boolean;
39
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-modern.d.ts","sourceRoot":"","sources":["../../../src/lib/protocols/mcp-modern.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAIL,KAAK,IAAI,EACV,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC5G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAWnD,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAClG,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC;AAEzF,MAAM,WAAW,0BAA0B;IACzC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA+UD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,GAAE,aAAa,EAAO,EAC/B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAoB3B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAC,CAyB5D;AAED,kGAAkG;AAClG,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,oBAAoB,CAAC,CA8B/B;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB/D"}
1
+ {"version":3,"file":"mcp-modern.d.ts","sourceRoot":"","sources":["../../../src/lib/protocols/mcp-modern.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAIL,KAAK,IAAI,EACV,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC5G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAWnD,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAClG,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC;AAEzF,MAAM,WAAW,0BAA0B;IACzC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAiWD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,GAAE,aAAa,EAAO,EAC/B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAqB3B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAC,CA0B5D;AAED,kGAAkG;AAClG,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,oBAAoB,CAAC,CA+B/B;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB/D"}
@@ -41,7 +41,9 @@ const knownLegacyConnections = /* @__PURE__ */ new Map();
41
41
  const MAX_CACHED_CONNECTIONS = 20;
42
42
  const LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1e3;
43
43
  const modernOAuthProviderIds = /* @__PURE__ */ new WeakMap();
44
+ const modernFetchFnIds = /* @__PURE__ */ new WeakMap();
44
45
  let nextModernOAuthProviderId = 0;
46
+ let nextModernFetchFnId = 0;
45
47
  let connectionGeneration = 0;
46
48
  function cacheDisambiguator(value) {
47
49
  return (0, import_node_crypto.createHmac)("sha256", "").update(value).digest("hex");
@@ -67,12 +69,23 @@ function oauthProviderCacheKey(provider) {
67
69
  }
68
70
  return key;
69
71
  }
70
- function connectionCacheKey(agentUrl, headers, signingCacheKey, authProvider) {
72
+ function fetchFnCacheKey(fetchFn) {
73
+ if (!fetchFn) return void 0;
74
+ let key = modernFetchFnIds.get(fetchFn);
75
+ if (!key) {
76
+ key = `fetch:${++nextModernFetchFnId}`;
77
+ modernFetchFnIds.set(fetchFn, key);
78
+ }
79
+ return key;
80
+ }
81
+ function connectionCacheKey(agentUrl, headers, signingCacheKey, authProvider, fetchFn) {
71
82
  const normalizedHeaders = Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]).sort(([left], [right]) => left.localeCompare(right));
72
83
  const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];
73
84
  if (signingCacheKey) parts.push(signingCacheKey);
74
85
  const providerKey = oauthProviderCacheKey(authProvider);
75
86
  if (providerKey) parts.push(providerKey);
87
+ const fetchKey = fetchFnCacheKey(fetchFn);
88
+ if (fetchKey) parts.push(fetchKey);
76
89
  return parts.join("::");
77
90
  }
78
91
  function isKnownLegacy(cacheKey) {
@@ -140,7 +153,7 @@ function evictLeastRecentlyUsed() {
140
153
  async function createNegotiatedClient(options, authHeaders) {
141
154
  const requestTimeoutMs = (0, import_abort.resolveRequestTimeoutMs)(options.requestTimeoutMs);
142
155
  const clientRequestTimeoutMs = (0, import_abort.resolveClientRequestTimeoutMs)(options.requestTimeoutMs);
143
- const rawNetworkFetch = (input, init) => fetch(input, init);
156
+ const rawNetworkFetch = options.fetchFn ?? ((input, init) => fetch(input, init));
144
157
  const networkFetch = (input, init) => (0, import_abort.withAbortSignal)(
145
158
  [options.signal, init?.signal],
146
159
  requestTimeoutMs,
@@ -224,10 +237,11 @@ async function attemptModernCall(options, toolName, args) {
224
237
  options.agentUrl,
225
238
  authHeaders,
226
239
  options.signingContext?.cacheKey,
227
- options.authProvider
240
+ options.authProvider,
241
+ options.fetchFn
228
242
  );
229
243
  if (isKnownLegacy(cacheKey)) return { handled: false };
230
- const guardedConnection = options.signal !== void 0 || options.requestTimeoutMs !== void 0;
244
+ const guardedConnection = options.signal !== void 0 || options.requestTimeoutMs !== void 0 || options.fetchFn !== void 0;
231
245
  let client;
232
246
  try {
233
247
  client = guardedConnection ? await createNegotiatedClient(options, authHeaders) : await getOrCreateModernConnection(cacheKey, options, authHeaders);
@@ -306,6 +320,7 @@ async function tryCallModernMCPTool(agentUrl, toolName, args, authToken, debugLo
306
320
  authProvider: options.authProvider,
307
321
  signal: options.signal,
308
322
  requestTimeoutMs: options.requestTimeoutMs,
323
+ fetchFn: options.fetchFn,
309
324
  handleLegacy: options.handleLegacy
310
325
  },
311
326
  toolName,
@@ -324,6 +339,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
324
339
  authProvider: options.authProvider,
325
340
  signal: options.signal,
326
341
  requestTimeoutMs: options.requestTimeoutMs,
342
+ fetchFn: options.fetchFn,
327
343
  handleLegacy: options.handleLegacy
328
344
  };
329
345
  const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);
@@ -350,7 +366,8 @@ async function tryListModernMCPTools(agentUrl, authToken, customHeaders, options
350
366
  signingContext: options.signingContext,
351
367
  authProvider: options.authProvider,
352
368
  signal: options.signal,
353
- requestTimeoutMs: options.requestTimeoutMs
369
+ requestTimeoutMs: options.requestTimeoutMs,
370
+ fetchFn: options.fetchFn
354
371
  };
355
372
  const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);
356
373
  let client;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/protocols/mcp-modern.ts"],"sourcesContent":["/**\n * MCP 2026-07-28 client path.\n *\n * The v2 SDK removed the experimental 2025 Tasks interception API. During the\n * migration window we therefore negotiate with the v2 client first and use it\n * only when the peer selects the modern protocol era. Legacy peers fall back\n * to mcp-tasks.ts, which keeps the existing v1 Tasks behavior intact.\n */\n\nimport {\n Client,\n StreamableHTTPClientTransport,\n type OAuthClientProvider as ModernOAuthClientProvider,\n type Tool,\n} from '@modelcontextprotocol/client';\nimport { createHmac } from 'node:crypto';\nimport { createMCPAuthHeaders } from '../auth';\nimport { is401Error } from '../errors';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport type { DebugLogEntry } from '../types/adcp';\nimport {\n isAbortOrTimeoutError,\n resolveClientRequestTimeoutMs,\n resolveRequestTimeoutMs,\n withAbortSignal,\n} from './abort';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\n\ntype CallToolResponse = {\n isError?: boolean;\n content?: Array<{ type: string; text?: string }>;\n [key: string]: unknown;\n};\n\nexport type ModernMCPAttempt = { handled: false } | { handled: true; response: CallToolResponse };\nexport type ModernMCPListAttempt = { handled: false } | { handled: true; tools: Tool[] };\n\nexport interface ModernMCPConnectionOptions {\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */\n handleLegacy?: boolean;\n}\n\ninterface ModernConnectionOptions {\n agentUrl: string;\n authToken?: string;\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n handleLegacy?: boolean;\n}\n\nconst modernConnections = new Map<string, Client>();\nconst legacyConnectionExpiresAt = new Map<string, number>();\nconst pendingModernConnections = new Map<string, Promise<Client>>();\nconst knownLegacyConnections = new Map<string, number>();\nconst MAX_CACHED_CONNECTIONS = 20;\nconst LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1000;\nconst modernOAuthProviderIds = new WeakMap<object, string>();\nlet nextModernOAuthProviderId = 0;\nlet connectionGeneration = 0;\n\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex');\n}\n\nfunction buildAuthHeaders(\n authToken: string | undefined,\n customHeaders: Record<string, string> | undefined,\n authProvider?: object\n): Record<string, string> {\n const filteredHeaders =\n authProvider || authToken\n ? Object.fromEntries(\n Object.entries(customHeaders ?? {}).filter(keyValue => {\n const key = keyValue[0].toLowerCase();\n return key !== 'authorization' && key !== 'x-adcp-auth';\n })\n )\n : customHeaders;\n return {\n ...filteredHeaders,\n ...(!authProvider && authToken ? createMCPAuthHeaders(authToken) : {}),\n };\n}\n\nfunction oauthProviderCacheKey(provider: object | undefined): string | undefined {\n if (!provider) return undefined;\n let key = modernOAuthProviderIds.get(provider);\n if (!key) {\n key = `oauth-provider:${++nextModernOAuthProviderId}`;\n modernOAuthProviderIds.set(provider, key);\n }\n return key;\n}\n\nfunction connectionCacheKey(\n agentUrl: string,\n headers: Record<string, string>,\n signingCacheKey?: string,\n authProvider?: object\n): string {\n const normalizedHeaders = Object.entries(headers)\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([left], [right]) => left.localeCompare(right));\n const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];\n if (signingCacheKey) parts.push(signingCacheKey);\n const providerKey = oauthProviderCacheKey(authProvider);\n if (providerKey) parts.push(providerKey);\n return parts.join('::');\n}\n\nfunction isKnownLegacy(cacheKey: string): boolean {\n const classifiedAt = knownLegacyConnections.get(cacheKey);\n if (classifiedAt === undefined) return false;\n if (Date.now() - classifiedAt > LEGACY_CLASSIFICATION_TTL_MS) {\n knownLegacyConnections.delete(cacheKey);\n return false;\n }\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, classifiedAt);\n return true;\n}\n\nfunction markKnownLegacy(cacheKey: string): void {\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, Date.now());\n while (knownLegacyConnections.size > MAX_CACHED_CONNECTIONS) {\n const oldest = knownLegacyConnections.keys().next().value;\n if (!oldest) break;\n knownLegacyConnections.delete(oldest);\n }\n}\n\nfunction httpStatusOf(error: unknown, depth = 0): number | undefined {\n if (!error || typeof error !== 'object' || depth > 4) return undefined;\n const candidate = error as { status?: unknown; code?: unknown; cause?: unknown; response?: { status?: unknown } };\n if (typeof candidate.status === 'number') return candidate.status;\n if (typeof candidate.response?.status === 'number') return candidate.response.status;\n if (typeof candidate.code === 'number' && candidate.code >= 100 && candidate.code <= 599) return candidate.code;\n return httpStatusOf(candidate.cause, depth + 1);\n}\n\nfunction withPerRequestTraceHeaders(fetchImpl: typeof fetch): typeof fetch {\n return (input, init) => {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n new Headers(init?.headers).forEach((value, key) => headers.set(key, value));\n for (const [key, value] of Object.entries(injectTraceHeaders())) headers.set(key, value);\n return fetchImpl(input, { ...init, headers });\n };\n}\n\nfunction getCachedConnection(cacheKey: string): Client | undefined {\n const client = modernConnections.get(cacheKey);\n if (client) {\n const legacyExpiry = legacyConnectionExpiresAt.get(cacheKey);\n if (legacyExpiry !== undefined && legacyExpiry <= Date.now()) {\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n void client.close().catch(() => {});\n return undefined;\n }\n modernConnections.delete(cacheKey);\n modernConnections.set(cacheKey, client);\n }\n return client;\n}\n\nfunction evictLeastRecentlyUsed(): void {\n if (modernConnections.size <= MAX_CACHED_CONNECTIONS) return;\n const oldestKey = modernConnections.keys().next().value;\n if (!oldestKey) return;\n const client = modernConnections.get(oldestKey);\n modernConnections.delete(oldestKey);\n legacyConnectionExpiresAt.delete(oldestKey);\n void client?.close().catch(() => {});\n}\n\nasync function createNegotiatedClient(\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const requestTimeoutMs = resolveRequestTimeoutMs(options.requestTimeoutMs);\n const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const rawNetworkFetch: typeof fetch = (input, init) => fetch(input, init);\n const networkFetch: typeof fetch = (input, init) =>\n withAbortSignal<Response>([options.signal, init?.signal], requestTimeoutMs, signal =>\n rawNetworkFetch(input, { ...init, signal })\n );\n const diagnosticFetch = wrapFetchWithTransportDiagnostics(wrapFetchWithSizeLimit(networkFetch));\n const signedFetch: typeof fetch = options.signingContext\n ? (buildAgentSigningFetch({\n upstream: diagnosticFetch,\n signing: options.signingContext.signing,\n getCapability: options.signingContext.getCapability,\n }) as typeof fetch)\n : diagnosticFetch;\n const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {\n requestInit: { headers: authHeaders, redirect: 'manual' },\n fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),\n ...(options.authProvider && {\n authProvider: options.authProvider as ModernOAuthClientProvider,\n }),\n });\n const client = new Client(\n { name: 'AdCP-Client', version: '1.0.0' },\n {\n versionNegotiation: {\n mode: 'auto',\n ...(clientRequestTimeoutMs !== undefined && { probe: { timeoutMs: clientRequestTimeoutMs } }),\n },\n }\n );\n\n try {\n await client.connect(transport, {\n ...(options.signal && { signal: options.signal }),\n ...(clientRequestTimeoutMs !== undefined && { timeout: clientRequestTimeoutMs }),\n });\n return client;\n } catch (error) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n }\n}\n\nasync function getOrCreateModernConnection(\n cacheKey: string,\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const cached = getCachedConnection(cacheKey);\n if (cached) return cached;\n\n const pending = pendingModernConnections.get(cacheKey);\n if (pending) return pending;\n\n const generation = connectionGeneration;\n const promise = createNegotiatedClient(options, authHeaders)\n .then(client => {\n if (\n (client.getProtocolEra() === 'modern' || options.handleLegacy === true) &&\n generation === connectionGeneration\n ) {\n modernConnections.set(cacheKey, client);\n if (client.getProtocolEra() === 'legacy') {\n legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);\n } else {\n legacyConnectionExpiresAt.delete(cacheKey);\n }\n evictLeastRecentlyUsed();\n } else if (generation !== connectionGeneration) {\n void client.close().catch(() => {});\n }\n return client;\n })\n .finally(() => {\n if (pendingModernConnections.get(cacheKey) === promise) pendingModernConnections.delete(cacheKey);\n });\n pendingModernConnections.set(cacheKey, promise);\n return promise;\n}\n\nasync function callOnModernClient(\n client: Client,\n toolName: string,\n args: Record<string, unknown>,\n signal?: AbortSignal,\n requestTimeoutMs?: number\n): Promise<CallToolResponse> {\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(requestTimeoutMs);\n return (await client.callTool(\n { name: toolName, arguments: args },\n {\n ...(signal && { signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n }\n )) as CallToolResponse;\n}\n\nasync function attemptModernCall(\n options: ModernConnectionOptions,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ModernMCPAttempt> {\n const authHeaders = buildAuthHeaders(options.authToken, options.customHeaders, options.authProvider);\n const cacheKey = connectionCacheKey(\n options.agentUrl,\n authHeaders,\n options.signingContext?.cacheKey,\n options.authProvider\n );\n if (isKnownLegacy(cacheKey)) return { handled: false };\n\n const guardedConnection = options.signal !== undefined || options.requestTimeoutMs !== undefined;\n let client: Client;\n try {\n client = guardedConnection\n ? await createNegotiatedClient(options, authHeaders)\n : await getOrCreateModernConnection(cacheKey, options, authHeaders);\n } catch (error) {\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) {\n markKnownLegacy(cacheKey);\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Modern Streamable HTTP is unavailable (HTTP ${status}); preserving the v1 transport path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n throw error;\n }\n\n if (client.getProtocolEra() !== 'modern') {\n if (options.handleLegacy === true) {\n options.debugLogs.push({\n type: 'info',\n message: `MCP: v2 client selected the legacy protocol era for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n } else {\n markKnownLegacy(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Server selected the legacy protocol era for ${toolName}; preserving the v1 Tasks path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n }\n\n options.debugLogs.push({\n type: 'success',\n message: `MCP: Negotiated protocol ${client.getNegotiatedProtocolVersion()} for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n\n try {\n const response = await callOnModernClient(client, toolName, args, options.signal, options.requestTimeoutMs);\n return { handled: true, response };\n } catch (error) {\n // A tool request may have reached the server even when its response was\n // lost. Never replay automatically: mutating AdCP tools depend on the\n // caller's explicit idempotency policy, not transport guesswork.\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n } finally {\n if (guardedConnection) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n }\n}\n\n/**\n * Try a tool call using the MCP 2026-07-28 protocol era.\n *\n * `handled: false` means the caller must use the existing v1 client. This is\n * deliberately a result rather than an exception because legacy negotiation\n * is normal during the transition window.\n */\nexport async function tryCallModernMCPTool(\n agentUrl: string,\n toolName: string,\n args: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPAttempt> {\n return withSpan('adcp.mcp.negotiate', { 'adcp.tool': toolName, 'http.url': agentUrl }, () =>\n signingContextStorage.run(options.signingContext, () =>\n attemptModernCall(\n {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs,\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n handleLegacy: options.handleLegacy,\n },\n toolName,\n args\n )\n )\n );\n}\n\n/**\n * Probe an endpoint with the official v2 client's auto negotiation.\n * `connected: false` lets endpoint discovery retain its v1 SSE fallback.\n */\nexport async function probeModernMCPConnection(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<{ connected: boolean; era?: 'legacy' | 'modern' }> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n handleLegacy: options.handleLegacy,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n return { connected: true, era: client.getProtocolEra() };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { connected: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\n/** List tools when the endpoint selected the modern era; otherwise let the v1 caller continue. */\nexport async function tryListModernMCPTools(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPListAttempt> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n if (client.getProtocolEra() !== 'modern') return { handled: false };\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const result = await client.listTools(undefined, {\n ...(options.signal && { signal: options.signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n });\n return { handled: true, tools: result.tools };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { handled: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\nexport async function closeModernMCPConnections(): Promise<void> {\n connectionGeneration++;\n const pending = [...pendingModernConnections.values()];\n pendingModernConnections.clear();\n const settled = await Promise.allSettled(pending);\n const clients = new Set(modernConnections.values());\n for (const result of settled) {\n if (result.status === 'fulfilled') clients.add(result.value);\n }\n modernConnections.clear();\n legacyConnectionExpiresAt.clear();\n knownLegacyConnections.clear();\n for (const client of clients) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n}\n"],"mappings":"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","names":["import_client"]}
1
+ {"version":3,"sources":["../../../src/lib/protocols/mcp-modern.ts"],"sourcesContent":["/**\n * MCP 2026-07-28 client path.\n *\n * The v2 SDK removed the experimental 2025 Tasks interception API. During the\n * migration window we therefore negotiate with the v2 client first and use it\n * only when the peer selects the modern protocol era. Legacy peers fall back\n * to mcp-tasks.ts, which keeps the existing v1 Tasks behavior intact.\n */\n\nimport {\n Client,\n StreamableHTTPClientTransport,\n type OAuthClientProvider as ModernOAuthClientProvider,\n type Tool,\n} from '@modelcontextprotocol/client';\nimport { createHmac } from 'node:crypto';\nimport { createMCPAuthHeaders } from '../auth';\nimport { is401Error } from '../errors';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport type { DebugLogEntry } from '../types/adcp';\nimport {\n isAbortOrTimeoutError,\n resolveClientRequestTimeoutMs,\n resolveRequestTimeoutMs,\n withAbortSignal,\n} from './abort';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\n\ntype CallToolResponse = {\n isError?: boolean;\n content?: Array<{ type: string; text?: string }>;\n [key: string]: unknown;\n};\n\nexport type ModernMCPAttempt = { handled: false } | { handled: true; response: CallToolResponse };\nexport type ModernMCPListAttempt = { handled: false } | { handled: true; tools: Tool[] };\n\nexport interface ModernMCPConnectionOptions {\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */\n handleLegacy?: boolean;\n}\n\ninterface ModernConnectionOptions {\n agentUrl: string;\n authToken?: string;\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n handleLegacy?: boolean;\n}\n\nconst modernConnections = new Map<string, Client>();\nconst legacyConnectionExpiresAt = new Map<string, number>();\nconst pendingModernConnections = new Map<string, Promise<Client>>();\nconst knownLegacyConnections = new Map<string, number>();\nconst MAX_CACHED_CONNECTIONS = 20;\nconst LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1000;\nconst modernOAuthProviderIds = new WeakMap<object, string>();\nconst modernFetchFnIds = new WeakMap<typeof fetch, string>();\nlet nextModernOAuthProviderId = 0;\nlet nextModernFetchFnId = 0;\nlet connectionGeneration = 0;\n\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex');\n}\n\nfunction buildAuthHeaders(\n authToken: string | undefined,\n customHeaders: Record<string, string> | undefined,\n authProvider?: object\n): Record<string, string> {\n const filteredHeaders =\n authProvider || authToken\n ? Object.fromEntries(\n Object.entries(customHeaders ?? {}).filter(keyValue => {\n const key = keyValue[0].toLowerCase();\n return key !== 'authorization' && key !== 'x-adcp-auth';\n })\n )\n : customHeaders;\n return {\n ...filteredHeaders,\n ...(!authProvider && authToken ? createMCPAuthHeaders(authToken) : {}),\n };\n}\n\nfunction oauthProviderCacheKey(provider: object | undefined): string | undefined {\n if (!provider) return undefined;\n let key = modernOAuthProviderIds.get(provider);\n if (!key) {\n key = `oauth-provider:${++nextModernOAuthProviderId}`;\n modernOAuthProviderIds.set(provider, key);\n }\n return key;\n}\n\nfunction fetchFnCacheKey(fetchFn: typeof fetch | undefined): string | undefined {\n if (!fetchFn) return undefined;\n let key = modernFetchFnIds.get(fetchFn);\n if (!key) {\n key = `fetch:${++nextModernFetchFnId}`;\n modernFetchFnIds.set(fetchFn, key);\n }\n return key;\n}\n\nfunction connectionCacheKey(\n agentUrl: string,\n headers: Record<string, string>,\n signingCacheKey?: string,\n authProvider?: object,\n fetchFn?: typeof fetch\n): string {\n const normalizedHeaders = Object.entries(headers)\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([left], [right]) => left.localeCompare(right));\n const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];\n if (signingCacheKey) parts.push(signingCacheKey);\n const providerKey = oauthProviderCacheKey(authProvider);\n if (providerKey) parts.push(providerKey);\n const fetchKey = fetchFnCacheKey(fetchFn);\n if (fetchKey) parts.push(fetchKey);\n return parts.join('::');\n}\n\nfunction isKnownLegacy(cacheKey: string): boolean {\n const classifiedAt = knownLegacyConnections.get(cacheKey);\n if (classifiedAt === undefined) return false;\n if (Date.now() - classifiedAt > LEGACY_CLASSIFICATION_TTL_MS) {\n knownLegacyConnections.delete(cacheKey);\n return false;\n }\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, classifiedAt);\n return true;\n}\n\nfunction markKnownLegacy(cacheKey: string): void {\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, Date.now());\n while (knownLegacyConnections.size > MAX_CACHED_CONNECTIONS) {\n const oldest = knownLegacyConnections.keys().next().value;\n if (!oldest) break;\n knownLegacyConnections.delete(oldest);\n }\n}\n\nfunction httpStatusOf(error: unknown, depth = 0): number | undefined {\n if (!error || typeof error !== 'object' || depth > 4) return undefined;\n const candidate = error as { status?: unknown; code?: unknown; cause?: unknown; response?: { status?: unknown } };\n if (typeof candidate.status === 'number') return candidate.status;\n if (typeof candidate.response?.status === 'number') return candidate.response.status;\n if (typeof candidate.code === 'number' && candidate.code >= 100 && candidate.code <= 599) return candidate.code;\n return httpStatusOf(candidate.cause, depth + 1);\n}\n\nfunction withPerRequestTraceHeaders(fetchImpl: typeof fetch): typeof fetch {\n return (input, init) => {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n new Headers(init?.headers).forEach((value, key) => headers.set(key, value));\n for (const [key, value] of Object.entries(injectTraceHeaders())) headers.set(key, value);\n return fetchImpl(input, { ...init, headers });\n };\n}\n\nfunction getCachedConnection(cacheKey: string): Client | undefined {\n const client = modernConnections.get(cacheKey);\n if (client) {\n const legacyExpiry = legacyConnectionExpiresAt.get(cacheKey);\n if (legacyExpiry !== undefined && legacyExpiry <= Date.now()) {\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n void client.close().catch(() => {});\n return undefined;\n }\n modernConnections.delete(cacheKey);\n modernConnections.set(cacheKey, client);\n }\n return client;\n}\n\nfunction evictLeastRecentlyUsed(): void {\n if (modernConnections.size <= MAX_CACHED_CONNECTIONS) return;\n const oldestKey = modernConnections.keys().next().value;\n if (!oldestKey) return;\n const client = modernConnections.get(oldestKey);\n modernConnections.delete(oldestKey);\n legacyConnectionExpiresAt.delete(oldestKey);\n void client?.close().catch(() => {});\n}\n\nasync function createNegotiatedClient(\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const requestTimeoutMs = resolveRequestTimeoutMs(options.requestTimeoutMs);\n const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const rawNetworkFetch: typeof fetch = options.fetchFn ?? ((input, init) => fetch(input, init));\n const networkFetch: typeof fetch = (input, init) =>\n withAbortSignal<Response>([options.signal, init?.signal], requestTimeoutMs, signal =>\n rawNetworkFetch(input, { ...init, signal })\n );\n const diagnosticFetch = wrapFetchWithTransportDiagnostics(wrapFetchWithSizeLimit(networkFetch));\n const signedFetch: typeof fetch = options.signingContext\n ? (buildAgentSigningFetch({\n upstream: diagnosticFetch,\n signing: options.signingContext.signing,\n getCapability: options.signingContext.getCapability,\n }) as typeof fetch)\n : diagnosticFetch;\n const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {\n requestInit: { headers: authHeaders, redirect: 'manual' },\n fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),\n ...(options.authProvider && {\n authProvider: options.authProvider as ModernOAuthClientProvider,\n }),\n });\n const client = new Client(\n { name: 'AdCP-Client', version: '1.0.0' },\n {\n versionNegotiation: {\n mode: 'auto',\n ...(clientRequestTimeoutMs !== undefined && { probe: { timeoutMs: clientRequestTimeoutMs } }),\n },\n }\n );\n\n try {\n await client.connect(transport, {\n ...(options.signal && { signal: options.signal }),\n ...(clientRequestTimeoutMs !== undefined && { timeout: clientRequestTimeoutMs }),\n });\n return client;\n } catch (error) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n }\n}\n\nasync function getOrCreateModernConnection(\n cacheKey: string,\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const cached = getCachedConnection(cacheKey);\n if (cached) return cached;\n\n const pending = pendingModernConnections.get(cacheKey);\n if (pending) return pending;\n\n const generation = connectionGeneration;\n const promise = createNegotiatedClient(options, authHeaders)\n .then(client => {\n if (\n (client.getProtocolEra() === 'modern' || options.handleLegacy === true) &&\n generation === connectionGeneration\n ) {\n modernConnections.set(cacheKey, client);\n if (client.getProtocolEra() === 'legacy') {\n legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);\n } else {\n legacyConnectionExpiresAt.delete(cacheKey);\n }\n evictLeastRecentlyUsed();\n } else if (generation !== connectionGeneration) {\n void client.close().catch(() => {});\n }\n return client;\n })\n .finally(() => {\n if (pendingModernConnections.get(cacheKey) === promise) pendingModernConnections.delete(cacheKey);\n });\n pendingModernConnections.set(cacheKey, promise);\n return promise;\n}\n\nasync function callOnModernClient(\n client: Client,\n toolName: string,\n args: Record<string, unknown>,\n signal?: AbortSignal,\n requestTimeoutMs?: number\n): Promise<CallToolResponse> {\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(requestTimeoutMs);\n return (await client.callTool(\n { name: toolName, arguments: args },\n {\n ...(signal && { signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n }\n )) as CallToolResponse;\n}\n\nasync function attemptModernCall(\n options: ModernConnectionOptions,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ModernMCPAttempt> {\n const authHeaders = buildAuthHeaders(options.authToken, options.customHeaders, options.authProvider);\n const cacheKey = connectionCacheKey(\n options.agentUrl,\n authHeaders,\n options.signingContext?.cacheKey,\n options.authProvider,\n options.fetchFn\n );\n if (isKnownLegacy(cacheKey)) return { handled: false };\n\n const guardedConnection =\n options.signal !== undefined || options.requestTimeoutMs !== undefined || options.fetchFn !== undefined;\n let client: Client;\n try {\n client = guardedConnection\n ? await createNegotiatedClient(options, authHeaders)\n : await getOrCreateModernConnection(cacheKey, options, authHeaders);\n } catch (error) {\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) {\n markKnownLegacy(cacheKey);\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Modern Streamable HTTP is unavailable (HTTP ${status}); preserving the v1 transport path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n throw error;\n }\n\n if (client.getProtocolEra() !== 'modern') {\n if (options.handleLegacy === true) {\n options.debugLogs.push({\n type: 'info',\n message: `MCP: v2 client selected the legacy protocol era for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n } else {\n markKnownLegacy(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Server selected the legacy protocol era for ${toolName}; preserving the v1 Tasks path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n }\n\n options.debugLogs.push({\n type: 'success',\n message: `MCP: Negotiated protocol ${client.getNegotiatedProtocolVersion()} for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n\n try {\n const response = await callOnModernClient(client, toolName, args, options.signal, options.requestTimeoutMs);\n return { handled: true, response };\n } catch (error) {\n // A tool request may have reached the server even when its response was\n // lost. Never replay automatically: mutating AdCP tools depend on the\n // caller's explicit idempotency policy, not transport guesswork.\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n } finally {\n if (guardedConnection) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n }\n}\n\n/**\n * Try a tool call using the MCP 2026-07-28 protocol era.\n *\n * `handled: false` means the caller must use the existing v1 client. This is\n * deliberately a result rather than an exception because legacy negotiation\n * is normal during the transition window.\n */\nexport async function tryCallModernMCPTool(\n agentUrl: string,\n toolName: string,\n args: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPAttempt> {\n return withSpan('adcp.mcp.negotiate', { 'adcp.tool': toolName, 'http.url': agentUrl }, () =>\n signingContextStorage.run(options.signingContext, () =>\n attemptModernCall(\n {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs,\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n handleLegacy: options.handleLegacy,\n },\n toolName,\n args\n )\n )\n );\n}\n\n/**\n * Probe an endpoint with the official v2 client's auto negotiation.\n * `connected: false` lets endpoint discovery retain its v1 SSE fallback.\n */\nexport async function probeModernMCPConnection(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<{ connected: boolean; era?: 'legacy' | 'modern' }> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n handleLegacy: options.handleLegacy,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n return { connected: true, era: client.getProtocolEra() };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { connected: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\n/** List tools when the endpoint selected the modern era; otherwise let the v1 caller continue. */\nexport async function tryListModernMCPTools(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPListAttempt> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n if (client.getProtocolEra() !== 'modern') return { handled: false };\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const result = await client.listTools(undefined, {\n ...(options.signal && { signal: options.signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n });\n return { handled: true, tools: result.tools };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { handled: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\nexport async function closeModernMCPConnections(): Promise<void> {\n connectionGeneration++;\n const pending = [...pendingModernConnections.values()];\n pendingModernConnections.clear();\n const settled = await Promise.allSettled(pending);\n const clients = new Set(modernConnections.values());\n for (const result of settled) {\n if (result.status === 'fulfilled') clients.add(result.value);\n }\n modernConnections.clear();\n legacyConnectionExpiresAt.clear();\n knownLegacyConnections.clear();\n for (const client of clients) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n}\n"],"mappings":"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","names":["import_client"]}
@@ -23,7 +23,9 @@ const knownLegacyConnections = /* @__PURE__ */ new Map();
23
23
  const MAX_CACHED_CONNECTIONS = 20;
24
24
  const LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1e3;
25
25
  const modernOAuthProviderIds = /* @__PURE__ */ new WeakMap();
26
+ const modernFetchFnIds = /* @__PURE__ */ new WeakMap();
26
27
  let nextModernOAuthProviderId = 0;
28
+ let nextModernFetchFnId = 0;
27
29
  let connectionGeneration = 0;
28
30
  function cacheDisambiguator(value) {
29
31
  return createHmac("sha256", "").update(value).digest("hex");
@@ -49,12 +51,23 @@ function oauthProviderCacheKey(provider) {
49
51
  }
50
52
  return key;
51
53
  }
52
- function connectionCacheKey(agentUrl, headers, signingCacheKey, authProvider) {
54
+ function fetchFnCacheKey(fetchFn) {
55
+ if (!fetchFn) return void 0;
56
+ let key = modernFetchFnIds.get(fetchFn);
57
+ if (!key) {
58
+ key = `fetch:${++nextModernFetchFnId}`;
59
+ modernFetchFnIds.set(fetchFn, key);
60
+ }
61
+ return key;
62
+ }
63
+ function connectionCacheKey(agentUrl, headers, signingCacheKey, authProvider, fetchFn) {
53
64
  const normalizedHeaders = Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]).sort(([left], [right]) => left.localeCompare(right));
54
65
  const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];
55
66
  if (signingCacheKey) parts.push(signingCacheKey);
56
67
  const providerKey = oauthProviderCacheKey(authProvider);
57
68
  if (providerKey) parts.push(providerKey);
69
+ const fetchKey = fetchFnCacheKey(fetchFn);
70
+ if (fetchKey) parts.push(fetchKey);
58
71
  return parts.join("::");
59
72
  }
60
73
  function isKnownLegacy(cacheKey) {
@@ -122,7 +135,7 @@ function evictLeastRecentlyUsed() {
122
135
  async function createNegotiatedClient(options, authHeaders) {
123
136
  const requestTimeoutMs = resolveRequestTimeoutMs(options.requestTimeoutMs);
124
137
  const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);
125
- const rawNetworkFetch = (input, init) => fetch(input, init);
138
+ const rawNetworkFetch = options.fetchFn ?? ((input, init) => fetch(input, init));
126
139
  const networkFetch = (input, init) => withAbortSignal(
127
140
  [options.signal, init?.signal],
128
141
  requestTimeoutMs,
@@ -206,10 +219,11 @@ async function attemptModernCall(options, toolName, args) {
206
219
  options.agentUrl,
207
220
  authHeaders,
208
221
  options.signingContext?.cacheKey,
209
- options.authProvider
222
+ options.authProvider,
223
+ options.fetchFn
210
224
  );
211
225
  if (isKnownLegacy(cacheKey)) return { handled: false };
212
- const guardedConnection = options.signal !== void 0 || options.requestTimeoutMs !== void 0;
226
+ const guardedConnection = options.signal !== void 0 || options.requestTimeoutMs !== void 0 || options.fetchFn !== void 0;
213
227
  let client;
214
228
  try {
215
229
  client = guardedConnection ? await createNegotiatedClient(options, authHeaders) : await getOrCreateModernConnection(cacheKey, options, authHeaders);
@@ -288,6 +302,7 @@ async function tryCallModernMCPTool(agentUrl, toolName, args, authToken, debugLo
288
302
  authProvider: options.authProvider,
289
303
  signal: options.signal,
290
304
  requestTimeoutMs: options.requestTimeoutMs,
305
+ fetchFn: options.fetchFn,
291
306
  handleLegacy: options.handleLegacy
292
307
  },
293
308
  toolName,
@@ -306,6 +321,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
306
321
  authProvider: options.authProvider,
307
322
  signal: options.signal,
308
323
  requestTimeoutMs: options.requestTimeoutMs,
324
+ fetchFn: options.fetchFn,
309
325
  handleLegacy: options.handleLegacy
310
326
  };
311
327
  const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);
@@ -332,7 +348,8 @@ async function tryListModernMCPTools(agentUrl, authToken, customHeaders, options
332
348
  signingContext: options.signingContext,
333
349
  authProvider: options.authProvider,
334
350
  signal: options.signal,
335
- requestTimeoutMs: options.requestTimeoutMs
351
+ requestTimeoutMs: options.requestTimeoutMs,
352
+ fetchFn: options.fetchFn
336
353
  };
337
354
  const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);
338
355
  let client;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/protocols/mcp-modern.ts"],"sourcesContent":["/**\n * MCP 2026-07-28 client path.\n *\n * The v2 SDK removed the experimental 2025 Tasks interception API. During the\n * migration window we therefore negotiate with the v2 client first and use it\n * only when the peer selects the modern protocol era. Legacy peers fall back\n * to mcp-tasks.ts, which keeps the existing v1 Tasks behavior intact.\n */\n\nimport {\n Client,\n StreamableHTTPClientTransport,\n type OAuthClientProvider as ModernOAuthClientProvider,\n type Tool,\n} from '@modelcontextprotocol/client';\nimport { createHmac } from 'node:crypto';\nimport { createMCPAuthHeaders } from '../auth';\nimport { is401Error } from '../errors';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport type { DebugLogEntry } from '../types/adcp';\nimport {\n isAbortOrTimeoutError,\n resolveClientRequestTimeoutMs,\n resolveRequestTimeoutMs,\n withAbortSignal,\n} from './abort';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\n\ntype CallToolResponse = {\n isError?: boolean;\n content?: Array<{ type: string; text?: string }>;\n [key: string]: unknown;\n};\n\nexport type ModernMCPAttempt = { handled: false } | { handled: true; response: CallToolResponse };\nexport type ModernMCPListAttempt = { handled: false } | { handled: true; tools: Tool[] };\n\nexport interface ModernMCPConnectionOptions {\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */\n handleLegacy?: boolean;\n}\n\ninterface ModernConnectionOptions {\n agentUrl: string;\n authToken?: string;\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n handleLegacy?: boolean;\n}\n\nconst modernConnections = new Map<string, Client>();\nconst legacyConnectionExpiresAt = new Map<string, number>();\nconst pendingModernConnections = new Map<string, Promise<Client>>();\nconst knownLegacyConnections = new Map<string, number>();\nconst MAX_CACHED_CONNECTIONS = 20;\nconst LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1000;\nconst modernOAuthProviderIds = new WeakMap<object, string>();\nlet nextModernOAuthProviderId = 0;\nlet connectionGeneration = 0;\n\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex');\n}\n\nfunction buildAuthHeaders(\n authToken: string | undefined,\n customHeaders: Record<string, string> | undefined,\n authProvider?: object\n): Record<string, string> {\n const filteredHeaders =\n authProvider || authToken\n ? Object.fromEntries(\n Object.entries(customHeaders ?? {}).filter(keyValue => {\n const key = keyValue[0].toLowerCase();\n return key !== 'authorization' && key !== 'x-adcp-auth';\n })\n )\n : customHeaders;\n return {\n ...filteredHeaders,\n ...(!authProvider && authToken ? createMCPAuthHeaders(authToken) : {}),\n };\n}\n\nfunction oauthProviderCacheKey(provider: object | undefined): string | undefined {\n if (!provider) return undefined;\n let key = modernOAuthProviderIds.get(provider);\n if (!key) {\n key = `oauth-provider:${++nextModernOAuthProviderId}`;\n modernOAuthProviderIds.set(provider, key);\n }\n return key;\n}\n\nfunction connectionCacheKey(\n agentUrl: string,\n headers: Record<string, string>,\n signingCacheKey?: string,\n authProvider?: object\n): string {\n const normalizedHeaders = Object.entries(headers)\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([left], [right]) => left.localeCompare(right));\n const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];\n if (signingCacheKey) parts.push(signingCacheKey);\n const providerKey = oauthProviderCacheKey(authProvider);\n if (providerKey) parts.push(providerKey);\n return parts.join('::');\n}\n\nfunction isKnownLegacy(cacheKey: string): boolean {\n const classifiedAt = knownLegacyConnections.get(cacheKey);\n if (classifiedAt === undefined) return false;\n if (Date.now() - classifiedAt > LEGACY_CLASSIFICATION_TTL_MS) {\n knownLegacyConnections.delete(cacheKey);\n return false;\n }\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, classifiedAt);\n return true;\n}\n\nfunction markKnownLegacy(cacheKey: string): void {\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, Date.now());\n while (knownLegacyConnections.size > MAX_CACHED_CONNECTIONS) {\n const oldest = knownLegacyConnections.keys().next().value;\n if (!oldest) break;\n knownLegacyConnections.delete(oldest);\n }\n}\n\nfunction httpStatusOf(error: unknown, depth = 0): number | undefined {\n if (!error || typeof error !== 'object' || depth > 4) return undefined;\n const candidate = error as { status?: unknown; code?: unknown; cause?: unknown; response?: { status?: unknown } };\n if (typeof candidate.status === 'number') return candidate.status;\n if (typeof candidate.response?.status === 'number') return candidate.response.status;\n if (typeof candidate.code === 'number' && candidate.code >= 100 && candidate.code <= 599) return candidate.code;\n return httpStatusOf(candidate.cause, depth + 1);\n}\n\nfunction withPerRequestTraceHeaders(fetchImpl: typeof fetch): typeof fetch {\n return (input, init) => {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n new Headers(init?.headers).forEach((value, key) => headers.set(key, value));\n for (const [key, value] of Object.entries(injectTraceHeaders())) headers.set(key, value);\n return fetchImpl(input, { ...init, headers });\n };\n}\n\nfunction getCachedConnection(cacheKey: string): Client | undefined {\n const client = modernConnections.get(cacheKey);\n if (client) {\n const legacyExpiry = legacyConnectionExpiresAt.get(cacheKey);\n if (legacyExpiry !== undefined && legacyExpiry <= Date.now()) {\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n void client.close().catch(() => {});\n return undefined;\n }\n modernConnections.delete(cacheKey);\n modernConnections.set(cacheKey, client);\n }\n return client;\n}\n\nfunction evictLeastRecentlyUsed(): void {\n if (modernConnections.size <= MAX_CACHED_CONNECTIONS) return;\n const oldestKey = modernConnections.keys().next().value;\n if (!oldestKey) return;\n const client = modernConnections.get(oldestKey);\n modernConnections.delete(oldestKey);\n legacyConnectionExpiresAt.delete(oldestKey);\n void client?.close().catch(() => {});\n}\n\nasync function createNegotiatedClient(\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const requestTimeoutMs = resolveRequestTimeoutMs(options.requestTimeoutMs);\n const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const rawNetworkFetch: typeof fetch = (input, init) => fetch(input, init);\n const networkFetch: typeof fetch = (input, init) =>\n withAbortSignal<Response>([options.signal, init?.signal], requestTimeoutMs, signal =>\n rawNetworkFetch(input, { ...init, signal })\n );\n const diagnosticFetch = wrapFetchWithTransportDiagnostics(wrapFetchWithSizeLimit(networkFetch));\n const signedFetch: typeof fetch = options.signingContext\n ? (buildAgentSigningFetch({\n upstream: diagnosticFetch,\n signing: options.signingContext.signing,\n getCapability: options.signingContext.getCapability,\n }) as typeof fetch)\n : diagnosticFetch;\n const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {\n requestInit: { headers: authHeaders, redirect: 'manual' },\n fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),\n ...(options.authProvider && {\n authProvider: options.authProvider as ModernOAuthClientProvider,\n }),\n });\n const client = new Client(\n { name: 'AdCP-Client', version: '1.0.0' },\n {\n versionNegotiation: {\n mode: 'auto',\n ...(clientRequestTimeoutMs !== undefined && { probe: { timeoutMs: clientRequestTimeoutMs } }),\n },\n }\n );\n\n try {\n await client.connect(transport, {\n ...(options.signal && { signal: options.signal }),\n ...(clientRequestTimeoutMs !== undefined && { timeout: clientRequestTimeoutMs }),\n });\n return client;\n } catch (error) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n }\n}\n\nasync function getOrCreateModernConnection(\n cacheKey: string,\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const cached = getCachedConnection(cacheKey);\n if (cached) return cached;\n\n const pending = pendingModernConnections.get(cacheKey);\n if (pending) return pending;\n\n const generation = connectionGeneration;\n const promise = createNegotiatedClient(options, authHeaders)\n .then(client => {\n if (\n (client.getProtocolEra() === 'modern' || options.handleLegacy === true) &&\n generation === connectionGeneration\n ) {\n modernConnections.set(cacheKey, client);\n if (client.getProtocolEra() === 'legacy') {\n legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);\n } else {\n legacyConnectionExpiresAt.delete(cacheKey);\n }\n evictLeastRecentlyUsed();\n } else if (generation !== connectionGeneration) {\n void client.close().catch(() => {});\n }\n return client;\n })\n .finally(() => {\n if (pendingModernConnections.get(cacheKey) === promise) pendingModernConnections.delete(cacheKey);\n });\n pendingModernConnections.set(cacheKey, promise);\n return promise;\n}\n\nasync function callOnModernClient(\n client: Client,\n toolName: string,\n args: Record<string, unknown>,\n signal?: AbortSignal,\n requestTimeoutMs?: number\n): Promise<CallToolResponse> {\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(requestTimeoutMs);\n return (await client.callTool(\n { name: toolName, arguments: args },\n {\n ...(signal && { signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n }\n )) as CallToolResponse;\n}\n\nasync function attemptModernCall(\n options: ModernConnectionOptions,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ModernMCPAttempt> {\n const authHeaders = buildAuthHeaders(options.authToken, options.customHeaders, options.authProvider);\n const cacheKey = connectionCacheKey(\n options.agentUrl,\n authHeaders,\n options.signingContext?.cacheKey,\n options.authProvider\n );\n if (isKnownLegacy(cacheKey)) return { handled: false };\n\n const guardedConnection = options.signal !== undefined || options.requestTimeoutMs !== undefined;\n let client: Client;\n try {\n client = guardedConnection\n ? await createNegotiatedClient(options, authHeaders)\n : await getOrCreateModernConnection(cacheKey, options, authHeaders);\n } catch (error) {\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) {\n markKnownLegacy(cacheKey);\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Modern Streamable HTTP is unavailable (HTTP ${status}); preserving the v1 transport path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n throw error;\n }\n\n if (client.getProtocolEra() !== 'modern') {\n if (options.handleLegacy === true) {\n options.debugLogs.push({\n type: 'info',\n message: `MCP: v2 client selected the legacy protocol era for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n } else {\n markKnownLegacy(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Server selected the legacy protocol era for ${toolName}; preserving the v1 Tasks path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n }\n\n options.debugLogs.push({\n type: 'success',\n message: `MCP: Negotiated protocol ${client.getNegotiatedProtocolVersion()} for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n\n try {\n const response = await callOnModernClient(client, toolName, args, options.signal, options.requestTimeoutMs);\n return { handled: true, response };\n } catch (error) {\n // A tool request may have reached the server even when its response was\n // lost. Never replay automatically: mutating AdCP tools depend on the\n // caller's explicit idempotency policy, not transport guesswork.\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n } finally {\n if (guardedConnection) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n }\n}\n\n/**\n * Try a tool call using the MCP 2026-07-28 protocol era.\n *\n * `handled: false` means the caller must use the existing v1 client. This is\n * deliberately a result rather than an exception because legacy negotiation\n * is normal during the transition window.\n */\nexport async function tryCallModernMCPTool(\n agentUrl: string,\n toolName: string,\n args: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPAttempt> {\n return withSpan('adcp.mcp.negotiate', { 'adcp.tool': toolName, 'http.url': agentUrl }, () =>\n signingContextStorage.run(options.signingContext, () =>\n attemptModernCall(\n {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs,\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n handleLegacy: options.handleLegacy,\n },\n toolName,\n args\n )\n )\n );\n}\n\n/**\n * Probe an endpoint with the official v2 client's auto negotiation.\n * `connected: false` lets endpoint discovery retain its v1 SSE fallback.\n */\nexport async function probeModernMCPConnection(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<{ connected: boolean; era?: 'legacy' | 'modern' }> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n handleLegacy: options.handleLegacy,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n return { connected: true, era: client.getProtocolEra() };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { connected: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\n/** List tools when the endpoint selected the modern era; otherwise let the v1 caller continue. */\nexport async function tryListModernMCPTools(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPListAttempt> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n if (client.getProtocolEra() !== 'modern') return { handled: false };\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const result = await client.listTools(undefined, {\n ...(options.signal && { signal: options.signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n });\n return { handled: true, tools: result.tools };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { handled: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\nexport async function closeModernMCPConnections(): Promise<void> {\n connectionGeneration++;\n const pending = [...pendingModernConnections.values()];\n pendingModernConnections.clear();\n const settled = await Promise.allSettled(pending);\n const clients = new Set(modernConnections.values());\n for (const result of settled) {\n if (result.status === 'fulfilled') clients.add(result.value);\n }\n modernConnections.clear();\n legacyConnectionExpiresAt.clear();\n knownLegacyConnections.clear();\n for (const client of clients) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/protocols/mcp-modern.ts"],"sourcesContent":["/**\n * MCP 2026-07-28 client path.\n *\n * The v2 SDK removed the experimental 2025 Tasks interception API. During the\n * migration window we therefore negotiate with the v2 client first and use it\n * only when the peer selects the modern protocol era. Legacy peers fall back\n * to mcp-tasks.ts, which keeps the existing v1 Tasks behavior intact.\n */\n\nimport {\n Client,\n StreamableHTTPClientTransport,\n type OAuthClientProvider as ModernOAuthClientProvider,\n type Tool,\n} from '@modelcontextprotocol/client';\nimport { createHmac } from 'node:crypto';\nimport { createMCPAuthHeaders } from '../auth';\nimport { is401Error } from '../errors';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport type { DebugLogEntry } from '../types/adcp';\nimport {\n isAbortOrTimeoutError,\n resolveClientRequestTimeoutMs,\n resolveRequestTimeoutMs,\n withAbortSignal,\n} from './abort';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\n\ntype CallToolResponse = {\n isError?: boolean;\n content?: Array<{ type: string; text?: string }>;\n [key: string]: unknown;\n};\n\nexport type ModernMCPAttempt = { handled: false } | { handled: true; response: CallToolResponse };\nexport type ModernMCPListAttempt = { handled: false } | { handled: true; tools: Tool[] };\n\nexport interface ModernMCPConnectionOptions {\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */\n handleLegacy?: boolean;\n}\n\ninterface ModernConnectionOptions {\n agentUrl: string;\n authToken?: string;\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n signingContext?: AgentSigningContext;\n authProvider?: object;\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n handleLegacy?: boolean;\n}\n\nconst modernConnections = new Map<string, Client>();\nconst legacyConnectionExpiresAt = new Map<string, number>();\nconst pendingModernConnections = new Map<string, Promise<Client>>();\nconst knownLegacyConnections = new Map<string, number>();\nconst MAX_CACHED_CONNECTIONS = 20;\nconst LEGACY_CLASSIFICATION_TTL_MS = 5 * 60 * 1000;\nconst modernOAuthProviderIds = new WeakMap<object, string>();\nconst modernFetchFnIds = new WeakMap<typeof fetch, string>();\nlet nextModernOAuthProviderId = 0;\nlet nextModernFetchFnId = 0;\nlet connectionGeneration = 0;\n\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex');\n}\n\nfunction buildAuthHeaders(\n authToken: string | undefined,\n customHeaders: Record<string, string> | undefined,\n authProvider?: object\n): Record<string, string> {\n const filteredHeaders =\n authProvider || authToken\n ? Object.fromEntries(\n Object.entries(customHeaders ?? {}).filter(keyValue => {\n const key = keyValue[0].toLowerCase();\n return key !== 'authorization' && key !== 'x-adcp-auth';\n })\n )\n : customHeaders;\n return {\n ...filteredHeaders,\n ...(!authProvider && authToken ? createMCPAuthHeaders(authToken) : {}),\n };\n}\n\nfunction oauthProviderCacheKey(provider: object | undefined): string | undefined {\n if (!provider) return undefined;\n let key = modernOAuthProviderIds.get(provider);\n if (!key) {\n key = `oauth-provider:${++nextModernOAuthProviderId}`;\n modernOAuthProviderIds.set(provider, key);\n }\n return key;\n}\n\nfunction fetchFnCacheKey(fetchFn: typeof fetch | undefined): string | undefined {\n if (!fetchFn) return undefined;\n let key = modernFetchFnIds.get(fetchFn);\n if (!key) {\n key = `fetch:${++nextModernFetchFnId}`;\n modernFetchFnIds.set(fetchFn, key);\n }\n return key;\n}\n\nfunction connectionCacheKey(\n agentUrl: string,\n headers: Record<string, string>,\n signingCacheKey?: string,\n authProvider?: object,\n fetchFn?: typeof fetch\n): string {\n const normalizedHeaders = Object.entries(headers)\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([left], [right]) => left.localeCompare(right));\n const parts = [agentUrl, `headers:${cacheDisambiguator(JSON.stringify(normalizedHeaders))}`];\n if (signingCacheKey) parts.push(signingCacheKey);\n const providerKey = oauthProviderCacheKey(authProvider);\n if (providerKey) parts.push(providerKey);\n const fetchKey = fetchFnCacheKey(fetchFn);\n if (fetchKey) parts.push(fetchKey);\n return parts.join('::');\n}\n\nfunction isKnownLegacy(cacheKey: string): boolean {\n const classifiedAt = knownLegacyConnections.get(cacheKey);\n if (classifiedAt === undefined) return false;\n if (Date.now() - classifiedAt > LEGACY_CLASSIFICATION_TTL_MS) {\n knownLegacyConnections.delete(cacheKey);\n return false;\n }\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, classifiedAt);\n return true;\n}\n\nfunction markKnownLegacy(cacheKey: string): void {\n knownLegacyConnections.delete(cacheKey);\n knownLegacyConnections.set(cacheKey, Date.now());\n while (knownLegacyConnections.size > MAX_CACHED_CONNECTIONS) {\n const oldest = knownLegacyConnections.keys().next().value;\n if (!oldest) break;\n knownLegacyConnections.delete(oldest);\n }\n}\n\nfunction httpStatusOf(error: unknown, depth = 0): number | undefined {\n if (!error || typeof error !== 'object' || depth > 4) return undefined;\n const candidate = error as { status?: unknown; code?: unknown; cause?: unknown; response?: { status?: unknown } };\n if (typeof candidate.status === 'number') return candidate.status;\n if (typeof candidate.response?.status === 'number') return candidate.response.status;\n if (typeof candidate.code === 'number' && candidate.code >= 100 && candidate.code <= 599) return candidate.code;\n return httpStatusOf(candidate.cause, depth + 1);\n}\n\nfunction withPerRequestTraceHeaders(fetchImpl: typeof fetch): typeof fetch {\n return (input, init) => {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n new Headers(init?.headers).forEach((value, key) => headers.set(key, value));\n for (const [key, value] of Object.entries(injectTraceHeaders())) headers.set(key, value);\n return fetchImpl(input, { ...init, headers });\n };\n}\n\nfunction getCachedConnection(cacheKey: string): Client | undefined {\n const client = modernConnections.get(cacheKey);\n if (client) {\n const legacyExpiry = legacyConnectionExpiresAt.get(cacheKey);\n if (legacyExpiry !== undefined && legacyExpiry <= Date.now()) {\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n void client.close().catch(() => {});\n return undefined;\n }\n modernConnections.delete(cacheKey);\n modernConnections.set(cacheKey, client);\n }\n return client;\n}\n\nfunction evictLeastRecentlyUsed(): void {\n if (modernConnections.size <= MAX_CACHED_CONNECTIONS) return;\n const oldestKey = modernConnections.keys().next().value;\n if (!oldestKey) return;\n const client = modernConnections.get(oldestKey);\n modernConnections.delete(oldestKey);\n legacyConnectionExpiresAt.delete(oldestKey);\n void client?.close().catch(() => {});\n}\n\nasync function createNegotiatedClient(\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const requestTimeoutMs = resolveRequestTimeoutMs(options.requestTimeoutMs);\n const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const rawNetworkFetch: typeof fetch = options.fetchFn ?? ((input, init) => fetch(input, init));\n const networkFetch: typeof fetch = (input, init) =>\n withAbortSignal<Response>([options.signal, init?.signal], requestTimeoutMs, signal =>\n rawNetworkFetch(input, { ...init, signal })\n );\n const diagnosticFetch = wrapFetchWithTransportDiagnostics(wrapFetchWithSizeLimit(networkFetch));\n const signedFetch: typeof fetch = options.signingContext\n ? (buildAgentSigningFetch({\n upstream: diagnosticFetch,\n signing: options.signingContext.signing,\n getCapability: options.signingContext.getCapability,\n }) as typeof fetch)\n : diagnosticFetch;\n const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {\n requestInit: { headers: authHeaders, redirect: 'manual' },\n fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),\n ...(options.authProvider && {\n authProvider: options.authProvider as ModernOAuthClientProvider,\n }),\n });\n const client = new Client(\n { name: 'AdCP-Client', version: '1.0.0' },\n {\n versionNegotiation: {\n mode: 'auto',\n ...(clientRequestTimeoutMs !== undefined && { probe: { timeoutMs: clientRequestTimeoutMs } }),\n },\n }\n );\n\n try {\n await client.connect(transport, {\n ...(options.signal && { signal: options.signal }),\n ...(clientRequestTimeoutMs !== undefined && { timeout: clientRequestTimeoutMs }),\n });\n return client;\n } catch (error) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n }\n}\n\nasync function getOrCreateModernConnection(\n cacheKey: string,\n options: ModernConnectionOptions,\n authHeaders: Record<string, string>\n): Promise<Client> {\n const cached = getCachedConnection(cacheKey);\n if (cached) return cached;\n\n const pending = pendingModernConnections.get(cacheKey);\n if (pending) return pending;\n\n const generation = connectionGeneration;\n const promise = createNegotiatedClient(options, authHeaders)\n .then(client => {\n if (\n (client.getProtocolEra() === 'modern' || options.handleLegacy === true) &&\n generation === connectionGeneration\n ) {\n modernConnections.set(cacheKey, client);\n if (client.getProtocolEra() === 'legacy') {\n legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);\n } else {\n legacyConnectionExpiresAt.delete(cacheKey);\n }\n evictLeastRecentlyUsed();\n } else if (generation !== connectionGeneration) {\n void client.close().catch(() => {});\n }\n return client;\n })\n .finally(() => {\n if (pendingModernConnections.get(cacheKey) === promise) pendingModernConnections.delete(cacheKey);\n });\n pendingModernConnections.set(cacheKey, promise);\n return promise;\n}\n\nasync function callOnModernClient(\n client: Client,\n toolName: string,\n args: Record<string, unknown>,\n signal?: AbortSignal,\n requestTimeoutMs?: number\n): Promise<CallToolResponse> {\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(requestTimeoutMs);\n return (await client.callTool(\n { name: toolName, arguments: args },\n {\n ...(signal && { signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n }\n )) as CallToolResponse;\n}\n\nasync function attemptModernCall(\n options: ModernConnectionOptions,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ModernMCPAttempt> {\n const authHeaders = buildAuthHeaders(options.authToken, options.customHeaders, options.authProvider);\n const cacheKey = connectionCacheKey(\n options.agentUrl,\n authHeaders,\n options.signingContext?.cacheKey,\n options.authProvider,\n options.fetchFn\n );\n if (isKnownLegacy(cacheKey)) return { handled: false };\n\n const guardedConnection =\n options.signal !== undefined || options.requestTimeoutMs !== undefined || options.fetchFn !== undefined;\n let client: Client;\n try {\n client = guardedConnection\n ? await createNegotiatedClient(options, authHeaders)\n : await getOrCreateModernConnection(cacheKey, options, authHeaders);\n } catch (error) {\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) {\n markKnownLegacy(cacheKey);\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Modern Streamable HTTP is unavailable (HTTP ${status}); preserving the v1 transport path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n throw error;\n }\n\n if (client.getProtocolEra() !== 'modern') {\n if (options.handleLegacy === true) {\n options.debugLogs.push({\n type: 'info',\n message: `MCP: v2 client selected the legacy protocol era for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n } else {\n markKnownLegacy(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n options.debugLogs.push({\n type: 'info',\n message: `MCP: Server selected the legacy protocol era for ${toolName}; preserving the v1 Tasks path`,\n timestamp: new Date().toISOString(),\n });\n return { handled: false };\n }\n }\n\n options.debugLogs.push({\n type: 'success',\n message: `MCP: Negotiated protocol ${client.getNegotiatedProtocolVersion()} for ${toolName}`,\n timestamp: new Date().toISOString(),\n });\n\n try {\n const response = await callOnModernClient(client, toolName, args, options.signal, options.requestTimeoutMs);\n return { handled: true, response };\n } catch (error) {\n // A tool request may have reached the server even when its response was\n // lost. Never replay automatically: mutating AdCP tools depend on the\n // caller's explicit idempotency policy, not transport guesswork.\n modernConnections.delete(cacheKey);\n legacyConnectionExpiresAt.delete(cacheKey);\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n throw error;\n } finally {\n if (guardedConnection) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n }\n}\n\n/**\n * Try a tool call using the MCP 2026-07-28 protocol era.\n *\n * `handled: false` means the caller must use the existing v1 client. This is\n * deliberately a result rather than an exception because legacy negotiation\n * is normal during the transition window.\n */\nexport async function tryCallModernMCPTool(\n agentUrl: string,\n toolName: string,\n args: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPAttempt> {\n return withSpan('adcp.mcp.negotiate', { 'adcp.tool': toolName, 'http.url': agentUrl }, () =>\n signingContextStorage.run(options.signingContext, () =>\n attemptModernCall(\n {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs,\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n handleLegacy: options.handleLegacy,\n },\n toolName,\n args\n )\n )\n );\n}\n\n/**\n * Probe an endpoint with the official v2 client's auto negotiation.\n * `connected: false` lets endpoint discovery retain its v1 SSE fallback.\n */\nexport async function probeModernMCPConnection(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<{ connected: boolean; era?: 'legacy' | 'modern' }> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n handleLegacy: options.handleLegacy,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n return { connected: true, era: client.getProtocolEra() };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { connected: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\n/** List tools when the endpoint selected the modern era; otherwise let the v1 caller continue. */\nexport async function tryListModernMCPTools(\n agentUrl: string,\n authToken?: string,\n customHeaders?: Record<string, string>,\n options: ModernMCPConnectionOptions = {}\n): Promise<ModernMCPListAttempt> {\n const connectionOptions: ModernConnectionOptions = {\n agentUrl,\n authToken,\n customHeaders,\n debugLogs: [],\n signingContext: options.signingContext,\n authProvider: options.authProvider,\n signal: options.signal,\n requestTimeoutMs: options.requestTimeoutMs,\n fetchFn: options.fetchFn,\n };\n const authHeaders = buildAuthHeaders(authToken, customHeaders, options.authProvider);\n let client: Client | undefined;\n try {\n client = await createNegotiatedClient(connectionOptions, authHeaders);\n if (client.getProtocolEra() !== 'modern') return { handled: false };\n const resolvedRequestTimeoutMs = resolveClientRequestTimeoutMs(options.requestTimeoutMs);\n const result = await client.listTools(undefined, {\n ...(options.signal && { signal: options.signal }),\n ...(resolvedRequestTimeoutMs !== undefined && { timeout: resolvedRequestTimeoutMs }),\n });\n return { handled: true, tools: result.tools };\n } catch (error) {\n if (is401Error(error) || isAbortOrTimeoutError(error)) throw error;\n const status = httpStatusOf(error);\n if (status === 404 || status === 405) return { handled: false };\n throw error;\n } finally {\n await client?.close().catch(() => {});\n }\n}\n\nexport async function closeModernMCPConnections(): Promise<void> {\n connectionGeneration++;\n const pending = [...pendingModernConnections.values()];\n pendingModernConnections.clear();\n const settled = await Promise.allSettled(pending);\n const clients = new Set(modernConnections.values());\n for (const result of settled) {\n if (result.status === 'fulfilled') clients.add(result.value);\n }\n modernConnections.clear();\n legacyConnectionExpiresAt.clear();\n knownLegacyConnections.clear();\n for (const client of clients) {\n try {\n await client.close();\n } catch {\n /* ignore close errors */\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -40,6 +40,12 @@ export interface MCPCallOptions {
40
40
  signal?: AbortSignal;
41
41
  /** Optional per-request timeout for connect and callTool. */
42
42
  requestTimeoutMs?: number;
43
+ /**
44
+ * Scoped fetch implementation used for MCP requests, OAuth discovery, and token exchange.
45
+ * Calls with a scoped fetcher use an isolated one-shot connection rather than the shared
46
+ * OAuth connection cache, so callers must not rely on cross-call MCP session state.
47
+ */
48
+ fetchFn?: typeof fetch;
43
49
  }
44
50
  /**
45
51
  * Result of an MCP connection attempt
@@ -123,6 +129,7 @@ export declare function connectMCP(options: {
123
129
  signingContext?: AgentSigningContext;
124
130
  signal?: AbortSignal;
125
131
  requestTimeoutMs?: number;
132
+ fetchFn?: typeof fetch;
126
133
  }): Promise<MCPConnectionResult>;
127
134
  /**
128
135
  * Call an MCP tool with OAuth support.
@@ -133,6 +140,10 @@ export declare function connectMCP(options: {
133
140
  * session/source/principal; the provider owns token refresh state for the
134
141
  * cached transport.
135
142
  *
143
+ * Supplying `fetchFn` opts out of connection reuse. Scoped fetchers commonly
144
+ * carry request- or tenant-specific network policy, so each call gets an
145
+ * isolated connection that is closed after the tool response.
146
+ *
136
147
  * Signing: this path consumes `options.signingContext` via the transport —
137
148
  * `connectMCP` attaches a signing-fetch wrapper at transport-creation time —
138
149
  * rather than via `signingContextStorage`. The OAuth cache key includes the
@@ -40,6 +40,12 @@ export interface MCPCallOptions {
40
40
  signal?: AbortSignal;
41
41
  /** Optional per-request timeout for connect and callTool. */
42
42
  requestTimeoutMs?: number;
43
+ /**
44
+ * Scoped fetch implementation used for MCP requests, OAuth discovery, and token exchange.
45
+ * Calls with a scoped fetcher use an isolated one-shot connection rather than the shared
46
+ * OAuth connection cache, so callers must not rely on cross-call MCP session state.
47
+ */
48
+ fetchFn?: typeof fetch;
43
49
  }
44
50
  /**
45
51
  * Result of an MCP connection attempt
@@ -123,6 +129,7 @@ export declare function connectMCP(options: {
123
129
  signingContext?: AgentSigningContext;
124
130
  signal?: AbortSignal;
125
131
  requestTimeoutMs?: number;
132
+ fetchFn?: typeof fetch;
126
133
  }): Promise<MCPConnectionResult>;
127
134
  /**
128
135
  * Call an MCP tool with OAuth support.
@@ -133,6 +140,10 @@ export declare function connectMCP(options: {
133
140
  * session/source/principal; the provider owns token refresh state for the
134
141
  * cached transport.
135
142
  *
143
+ * Supplying `fetchFn` opts out of connection reuse. Scoped fetchers commonly
144
+ * carry request- or tenant-specific network policy, so each call gets an
145
+ * isolated connection that is closed after the tool response.
146
+ *
136
147
  * Signing: this path consumes `options.signingContext` via the transport —
137
148
  * `connectMCP` attaches a signing-fetch wrapper at transport-creation time —
138
149
  * rather than via `signingContextStorage`. The OAuth cache key includes the