@adcp/sdk 12.0.3 → 12.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/advanced.d.mts +2 -1
- package/dist/lib/advanced.d.ts +2 -1
- package/dist/lib/advanced.d.ts.map +1 -1
- package/dist/lib/advanced.js +4 -0
- package/dist/lib/advanced.js.map +1 -1
- package/dist/lib/advanced.mjs +11 -1
- package/dist/lib/advanced.mjs.map +1 -1
- package/dist/lib/protocols/mcp-modern.d.mts +1 -0
- package/dist/lib/protocols/mcp-modern.d.ts +1 -0
- package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
- package/dist/lib/protocols/mcp-modern.js +22 -5
- package/dist/lib/protocols/mcp-modern.js.map +1 -1
- package/dist/lib/protocols/mcp-modern.mjs +22 -5
- package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
- package/dist/lib/protocols/mcp.d.mts +11 -0
- package/dist/lib/protocols/mcp.d.ts +11 -0
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +25 -8
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/protocols/mcp.mjs +25 -8
- package/dist/lib/protocols/mcp.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -1
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +21 -13
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +21 -13
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +8 -2
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +8 -2
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/package.json +2 -2
package/dist/lib/advanced.d.mts
CHANGED
|
@@ -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';
|
package/dist/lib/advanced.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/lib/advanced.js
CHANGED
|
@@ -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
|
});
|
package/dist/lib/advanced.js.map
CHANGED
|
@@ -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 {
|
|
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":[]}
|
package/dist/lib/advanced.mjs
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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;
|
|
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
|
|
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
|
|
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
|