@adcp/sdk 15.3.0 → 15.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/advanced.d.mts +2 -2
- package/dist/lib/advanced.d.ts +2 -2
- package/dist/lib/advanced.js +8 -2
- package/dist/lib/advanced.mjs +8 -2
- package/dist/lib/core/AgentClient.d.mts +4 -0
- package/dist/lib/core/AgentClient.d.ts +4 -0
- package/dist/lib/core/AgentClient.js +8 -0
- package/dist/lib/core/AgentClient.mjs +8 -0
- package/dist/lib/core/SingleAgentClient.d.mts +154 -0
- package/dist/lib/core/SingleAgentClient.d.ts +154 -0
- package/dist/lib/core/SingleAgentClient.js +661 -23
- package/dist/lib/core/SingleAgentClient.mjs +666 -23
- package/dist/lib/core/agent-discovery-cache.d.mts +103 -0
- package/dist/lib/core/agent-discovery-cache.d.ts +103 -0
- package/dist/lib/core/agent-discovery-cache.js +121 -0
- package/dist/lib/core/agent-discovery-cache.mjs +92 -0
- package/dist/lib/index.d.mts +5 -3
- package/dist/lib/index.d.ts +5 -3
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.mjs +6 -0
- package/dist/lib/protocols/index.d.mts +2 -2
- package/dist/lib/protocols/index.d.ts +2 -2
- package/dist/lib/protocols/index.js +1 -1
- package/dist/lib/protocols/index.mjs +1 -1
- package/dist/lib/protocols/mcp-call-context.d.mts +109 -0
- package/dist/lib/protocols/mcp-call-context.d.ts +109 -0
- package/dist/lib/protocols/mcp-call-context.js +221 -0
- package/dist/lib/protocols/mcp-call-context.mjs +186 -0
- package/dist/lib/protocols/mcp-modern.d.mts +9 -1
- package/dist/lib/protocols/mcp-modern.d.ts +9 -1
- package/dist/lib/protocols/mcp-modern.js +180 -104
- package/dist/lib/protocols/mcp-modern.mjs +193 -104
- package/dist/lib/protocols/mcp-scope.d.mts +15 -0
- package/dist/lib/protocols/mcp-scope.d.ts +15 -0
- package/dist/lib/protocols/mcp.d.mts +4 -2
- package/dist/lib/protocols/mcp.d.ts +4 -2
- package/dist/lib/protocols/mcp.js +178 -154
- package/dist/lib/protocols/mcp.mjs +189 -153
- package/dist/lib/protocols/transportDiagnostics.d.mts +33 -1
- package/dist/lib/protocols/transportDiagnostics.d.ts +33 -1
- package/dist/lib/protocols/transportDiagnostics.js +128 -12
- package/dist/lib/protocols/transportDiagnostics.mjs +128 -12
- package/dist/lib/reporting/gcs/index.d.mts +2 -0
- package/dist/lib/reporting/gcs/index.d.ts +2 -0
- package/dist/lib/reporting/gcs/index.js +3 -0
- package/dist/lib/reporting/gcs/index.mjs +2 -0
- package/dist/lib/reporting/gcs/row-provider.d.mts +32 -0
- package/dist/lib/reporting/gcs/row-provider.d.ts +32 -0
- package/dist/lib/reporting/gcs/row-provider.js +205 -0
- package/dist/lib/reporting/gcs/row-provider.mjs +188 -0
- package/dist/lib/reporting/ledger/change-feed.d.mts +41 -0
- package/dist/lib/reporting/ledger/change-feed.d.ts +41 -0
- package/dist/lib/reporting/ledger/change-feed.js +101 -0
- package/dist/lib/reporting/ledger/change-feed.mjs +74 -0
- package/dist/lib/reporting/ledger/handler.d.mts +6 -0
- package/dist/lib/reporting/ledger/handler.d.ts +6 -0
- package/dist/lib/reporting/ledger/handler.js +51 -8
- package/dist/lib/reporting/ledger/handler.mjs +50 -8
- package/dist/lib/reporting/ledger/index.d.mts +5 -0
- package/dist/lib/reporting/ledger/index.d.ts +5 -0
- package/dist/lib/reporting/ledger/index.js +11 -1
- package/dist/lib/reporting/ledger/index.mjs +5 -0
- package/dist/lib/reporting/ledger/lifecycle.js +3 -2
- package/dist/lib/reporting/ledger/lifecycle.mjs +3 -2
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.js +26 -6
- package/dist/lib/reporting/ledger/managed-postgres.mjs +26 -6
- package/dist/lib/reporting/ledger/managed.d.mts +9 -0
- package/dist/lib/reporting/ledger/managed.d.ts +9 -0
- package/dist/lib/reporting/ledger/managed.js +18 -0
- package/dist/lib/reporting/ledger/managed.mjs +18 -0
- package/dist/lib/reporting/ledger/postgres.d.mts +179 -1
- package/dist/lib/reporting/ledger/postgres.d.ts +179 -1
- package/dist/lib/reporting/ledger/postgres.js +882 -19
- package/dist/lib/reporting/ledger/postgres.mjs +890 -19
- package/dist/lib/reporting/ledger/producer.js +13 -3
- package/dist/lib/reporting/ledger/producer.mjs +13 -3
- package/dist/lib/reporting/ledger/revision-metadata.d.mts +17 -0
- package/dist/lib/reporting/ledger/revision-metadata.d.ts +17 -0
- package/dist/lib/reporting/ledger/revision-metadata.js +71 -0
- package/dist/lib/reporting/ledger/revision-metadata.mjs +44 -0
- package/dist/lib/reporting/ledger/row-encoding.d.mts +128 -0
- package/dist/lib/reporting/ledger/row-encoding.d.ts +128 -0
- package/dist/lib/reporting/ledger/row-encoding.js +355 -0
- package/dist/lib/reporting/ledger/row-encoding.mjs +315 -0
- package/dist/lib/reporting/ledger/row-storage-errors.d.mts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.d.ts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.js +41 -0
- package/dist/lib/reporting/ledger/row-storage-errors.mjs +16 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.js +234 -0
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +208 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.js +281 -0
- package/dist/lib/reporting/ledger/row-storage-object.mjs +239 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +51 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +51 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.js +152 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +119 -0
- package/dist/lib/reporting/ledger/row-storage.d.mts +224 -0
- package/dist/lib/reporting/ledger/row-storage.d.ts +224 -0
- package/dist/lib/reporting/ledger/row-storage.js +692 -0
- package/dist/lib/reporting/ledger/row-storage.mjs +680 -0
- package/dist/lib/reporting/ledger/types.d.mts +45 -0
- package/dist/lib/reporting/ledger/types.d.ts +45 -0
- package/dist/lib/reporting/service/index.d.mts +41 -1
- package/dist/lib/reporting/service/index.d.ts +41 -1
- package/dist/lib/reporting/service/index.js +68 -1
- package/dist/lib/reporting/service/index.mjs +70 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.js +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +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.mjs +3 -3
- package/docs/README.md +1 -1
- package/docs/TYPE-SUMMARY.md +35 -2
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +142 -0
- package/docs/guides/EXISTING-PLATFORM.md +43 -12
- package/docs/guides/REPORTING-LEDGER.md +209 -0
- package/docs/llms.txt +4 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/recipes/verifying-inbound-webhooks.md +8 -0
- package/package.json +1 -1
|
@@ -35,6 +35,20 @@ import {
|
|
|
35
35
|
registerMCPConnectionScopePending
|
|
36
36
|
} from "./mcp-scope.mjs";
|
|
37
37
|
import { terminateSessionBestEffort } from "./session-termination.mjs";
|
|
38
|
+
import {
|
|
39
|
+
applyMCPCallHeaders,
|
|
40
|
+
isCorrelationHeader,
|
|
41
|
+
withAmbientIdentityHeaders,
|
|
42
|
+
closeWhenIdle,
|
|
43
|
+
linkedCallSignal,
|
|
44
|
+
joinPendingConnection,
|
|
45
|
+
RETRY_CONNECT,
|
|
46
|
+
requestTimeoutFor,
|
|
47
|
+
runCallPhase,
|
|
48
|
+
runWithMCPCallContext,
|
|
49
|
+
splitConnectionHeaders,
|
|
50
|
+
trackConnectionUse
|
|
51
|
+
} from "./mcp-call-context.mjs";
|
|
38
52
|
import { createAgentTransportFetch } from "../net/agent-transport-fetch.mjs";
|
|
39
53
|
const connectionCache = /* @__PURE__ */ new Map();
|
|
40
54
|
const pendingConnections = /* @__PURE__ */ new Map();
|
|
@@ -43,11 +57,9 @@ const pendingOAuthConnections = /* @__PURE__ */ new Map();
|
|
|
43
57
|
const streamableTransports = /* @__PURE__ */ new WeakMap();
|
|
44
58
|
const oauthProviderIds = /* @__PURE__ */ new WeakMap();
|
|
45
59
|
const transportFetchFnIds = /* @__PURE__ */ new WeakMap();
|
|
46
|
-
const transportSignalIds = /* @__PURE__ */ new WeakMap();
|
|
47
60
|
const MAX_CACHED_CONNECTIONS = 20;
|
|
48
61
|
let nextOAuthProviderId = 0;
|
|
49
62
|
let nextTransportFetchFnId = 0;
|
|
50
|
-
let nextTransportSignalId = 0;
|
|
51
63
|
let connectionGeneration = 0;
|
|
52
64
|
let oauthConnectionGeneration = 0;
|
|
53
65
|
async function closeMCPClient(client, terminateSession = true) {
|
|
@@ -67,7 +79,7 @@ function trackStreamableHTTPUrl(url) {
|
|
|
67
79
|
if (oldest) knownStreamableHTTPUrls.delete(oldest);
|
|
68
80
|
}
|
|
69
81
|
}
|
|
70
|
-
function connectionCacheKey(agentUrl, authToken, signingCacheKey, authHeaders, transportFetch,
|
|
82
|
+
function connectionCacheKey(agentUrl, authToken, signingCacheKey, authHeaders, transportFetch, allowPrivateIp) {
|
|
71
83
|
const parts = [agentUrl];
|
|
72
84
|
const fingerprint = authToken ?? extractAuthHeader(authHeaders);
|
|
73
85
|
if (fingerprint) parts.push(cacheDisambiguator(fingerprint));
|
|
@@ -75,8 +87,6 @@ function connectionCacheKey(agentUrl, authToken, signingCacheKey, authHeaders, t
|
|
|
75
87
|
if (headersKey) parts.push(`headers:${headersKey}`);
|
|
76
88
|
if (signingCacheKey) parts.push(signingCacheKey);
|
|
77
89
|
if (transportFetch) parts.push(`fetch:${getTransportFetchFnDisambiguator(transportFetch)}`);
|
|
78
|
-
if (signal) parts.push(`signal:${getTransportSignalDisambiguator(signal)}`);
|
|
79
|
-
if (requestTimeoutMs !== void 0) parts.push(`timeout:${requestTimeoutMs}`);
|
|
80
90
|
if (allowPrivateIp !== void 0) parts.push(`allow-private-ip:${allowPrivateIp}`);
|
|
81
91
|
const scopeKey = currentMCPConnectionScopeKey();
|
|
82
92
|
if (scopeKey) parts.push(scopeKey);
|
|
@@ -94,18 +104,19 @@ function extractAuthHeader(headers) {
|
|
|
94
104
|
return void 0;
|
|
95
105
|
}
|
|
96
106
|
function headersCacheDisambiguator(headers) {
|
|
97
|
-
const entries = Object.entries(headers
|
|
98
|
-
const lower = key.toLowerCase();
|
|
99
|
-
return lower !== "traceparent" && lower !== "tracestate" && lower !== "baggage";
|
|
100
|
-
}).map(([key, value]) => [key.toLowerCase(), value]).sort(([a], [b]) => a.localeCompare(b));
|
|
107
|
+
const entries = Object.entries(splitConnectionHeaders(headers).identity).map(([key, value]) => [key.toLowerCase(), value]).sort(([a], [b]) => a.localeCompare(b));
|
|
101
108
|
return entries.length > 0 ? cacheDisambiguator(JSON.stringify(entries)) : void 0;
|
|
102
109
|
}
|
|
103
|
-
function withPerRequestTraceHeaders(fetchImpl) {
|
|
110
|
+
function withPerRequestTraceHeaders(fetchImpl, directDefaults) {
|
|
104
111
|
return (input, init) => {
|
|
105
112
|
const headers = new Headers(input instanceof Request ? input.headers : void 0);
|
|
106
113
|
new Headers(init?.headers).forEach((value, key) => headers.set(key, value));
|
|
107
|
-
|
|
108
|
-
return fetchImpl(input, { ...init, headers });
|
|
114
|
+
applyMCPCallHeaders(headers, directDefaults);
|
|
115
|
+
if (headers.has("traceparent")) return fetchImpl(input, { ...init, headers, ...linkedCallSignal(init) });
|
|
116
|
+
for (const [key, value] of Object.entries(injectTraceHeaders())) {
|
|
117
|
+
if (isCorrelationHeader(key) && !headers.has(key)) headers.set(key, value);
|
|
118
|
+
}
|
|
119
|
+
return fetchImpl(input, { ...init, headers, ...linkedCallSignal(init) });
|
|
109
120
|
};
|
|
110
121
|
}
|
|
111
122
|
function getCachedConnection(key) {
|
|
@@ -122,7 +133,7 @@ function evictLeastRecentlyUsed() {
|
|
|
122
133
|
if (!lruKey) return;
|
|
123
134
|
const oldClient = connectionCache.get(lruKey);
|
|
124
135
|
connectionCache.delete(lruKey);
|
|
125
|
-
if (oldClient) void closeMCPClient(oldClient).catch(() => {
|
|
136
|
+
if (oldClient) void closeWhenIdle(oldClient, () => closeMCPClient(oldClient)).catch(() => {
|
|
126
137
|
});
|
|
127
138
|
}
|
|
128
139
|
function evictLeastRecentlyUsedOAuth() {
|
|
@@ -131,7 +142,7 @@ function evictLeastRecentlyUsedOAuth() {
|
|
|
131
142
|
if (!lruKey) return;
|
|
132
143
|
const oldClient = oauthConnectionCache.get(lruKey);
|
|
133
144
|
oauthConnectionCache.delete(lruKey);
|
|
134
|
-
if (oldClient) void closeMCPClient(oldClient).catch(() => {
|
|
145
|
+
if (oldClient) void closeWhenIdle(oldClient, () => closeMCPClient(oldClient)).catch(() => {
|
|
135
146
|
});
|
|
136
147
|
}
|
|
137
148
|
async function closeOAuthConnections() {
|
|
@@ -172,31 +183,37 @@ async function closeMCPConnections() {
|
|
|
172
183
|
await closeModernMCPConnections();
|
|
173
184
|
}
|
|
174
185
|
async function getOrCreateConnection(cacheKey, baseUrl, authHeaders, debugLogs, label, transportFetch, requestOptions = {}) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
throw new Error(`MCP ${label} completed after connection teardown`);
|
|
186
|
+
for (let attempt = 0; ; attempt++) {
|
|
187
|
+
const cached = getCachedConnection(cacheKey);
|
|
188
|
+
if (cached) return cached;
|
|
189
|
+
const pending = pendingConnections.get(cacheKey);
|
|
190
|
+
if (pending) {
|
|
191
|
+
const joined = await joinPendingConnection(pending, requestOptions, attempt);
|
|
192
|
+
if (joined === RETRY_CONNECT) continue;
|
|
193
|
+
return joined;
|
|
185
194
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
const generation = connectionGeneration;
|
|
196
|
+
const promise = connectMCPWithFallback(baseUrl, authHeaders, debugLogs, label, transportFetch, requestOptions).then(async (client) => {
|
|
197
|
+
if (generation !== connectionGeneration) {
|
|
198
|
+
await closeMCPClient(client).catch(() => {
|
|
199
|
+
});
|
|
200
|
+
throw new Error(`MCP ${label} completed after connection teardown`);
|
|
201
|
+
}
|
|
202
|
+
connectionCache.set(cacheKey, client);
|
|
203
|
+
registerMCPConnectionScopeCleanup("legacy", cacheKey, async () => {
|
|
204
|
+
if (connectionCache.get(cacheKey) !== client) return;
|
|
205
|
+
connectionCache.delete(cacheKey);
|
|
206
|
+
await closeMCPClient(client);
|
|
207
|
+
});
|
|
208
|
+
evictLeastRecentlyUsed();
|
|
209
|
+
return client;
|
|
210
|
+
}).finally(() => {
|
|
211
|
+
if (pendingConnections.get(cacheKey) === promise) pendingConnections.delete(cacheKey);
|
|
191
212
|
});
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
197
|
-
pendingConnections.set(cacheKey, promise);
|
|
198
|
-
registerMCPConnectionScopePending(promise);
|
|
199
|
-
return promise;
|
|
213
|
+
pendingConnections.set(cacheKey, promise);
|
|
214
|
+
registerMCPConnectionScopePending(promise);
|
|
215
|
+
return promise;
|
|
216
|
+
}
|
|
200
217
|
}
|
|
201
218
|
function getOAuthProviderDisambiguator(authProvider) {
|
|
202
219
|
let id = oauthProviderIds.get(authProvider);
|
|
@@ -214,25 +231,15 @@ function getTransportFetchFnDisambiguator(fetchFn) {
|
|
|
214
231
|
}
|
|
215
232
|
return id;
|
|
216
233
|
}
|
|
217
|
-
function getTransportSignalDisambiguator(signal) {
|
|
218
|
-
let id = transportSignalIds.get(signal);
|
|
219
|
-
if (!id) {
|
|
220
|
-
id = cacheDisambiguator(`transport-signal:${++nextTransportSignalId}`);
|
|
221
|
-
transportSignalIds.set(signal, id);
|
|
222
|
-
}
|
|
223
|
-
return id;
|
|
224
|
-
}
|
|
225
234
|
function customHeadersDisambiguator(customHeaders) {
|
|
226
235
|
return headersCacheDisambiguator(customHeaders);
|
|
227
236
|
}
|
|
228
|
-
function oauthConnectionCacheKey(agentUrl, authProvider, signingCacheKey, customHeaders, fetchFn,
|
|
237
|
+
function oauthConnectionCacheKey(agentUrl, authProvider, signingCacheKey, customHeaders, fetchFn, allowPrivateIp) {
|
|
229
238
|
const parts = [`${agentUrl}::oauth:${getOAuthProviderDisambiguator(authProvider)}`];
|
|
230
239
|
if (signingCacheKey) parts.push(signingCacheKey);
|
|
231
240
|
const headersKey = customHeadersDisambiguator(customHeaders);
|
|
232
241
|
if (headersKey) parts.push(`headers:${headersKey}`);
|
|
233
242
|
if (fetchFn) parts.push(`fetch:${getTransportFetchFnDisambiguator(fetchFn)}`);
|
|
234
|
-
if (signal) parts.push(`signal:${getTransportSignalDisambiguator(signal)}`);
|
|
235
|
-
if (requestTimeoutMs !== void 0) parts.push(`timeout:${requestTimeoutMs}`);
|
|
236
243
|
if (allowPrivateIp !== void 0) parts.push(`allow-private-ip:${allowPrivateIp}`);
|
|
237
244
|
const scopeKey = currentMCPConnectionScopeKey();
|
|
238
245
|
if (scopeKey) parts.push(scopeKey);
|
|
@@ -247,39 +254,52 @@ function getCachedOAuthConnection(key) {
|
|
|
247
254
|
return client;
|
|
248
255
|
}
|
|
249
256
|
async function getOrCreateOAuthConnection(cacheKey, options) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
});
|
|
259
|
-
throw new Error("OAuth MCP connection completed after connection teardown");
|
|
257
|
+
for (let attempt = 0; ; attempt++) {
|
|
258
|
+
const cached = getCachedOAuthConnection(cacheKey);
|
|
259
|
+
if (cached) return cached;
|
|
260
|
+
const pending = pendingOAuthConnections.get(cacheKey);
|
|
261
|
+
if (pending) {
|
|
262
|
+
const joined = await joinPendingConnection(pending, options, attempt);
|
|
263
|
+
if (joined === RETRY_CONNECT) continue;
|
|
264
|
+
return joined;
|
|
260
265
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
+
const generation = oauthConnectionGeneration;
|
|
267
|
+
const promise = connectMCP(options).then(async ({ client }) => {
|
|
268
|
+
if (generation !== oauthConnectionGeneration) {
|
|
269
|
+
await closeMCPClient(client).catch(() => {
|
|
270
|
+
});
|
|
271
|
+
throw new Error("OAuth MCP connection completed after connection teardown");
|
|
272
|
+
}
|
|
273
|
+
oauthConnectionCache.set(cacheKey, client);
|
|
274
|
+
registerMCPConnectionScopeCleanup("oauth", cacheKey, async () => {
|
|
275
|
+
if (oauthConnectionCache.get(cacheKey) !== client) return;
|
|
276
|
+
oauthConnectionCache.delete(cacheKey);
|
|
277
|
+
await closeMCPClient(client);
|
|
278
|
+
});
|
|
279
|
+
evictLeastRecentlyUsedOAuth();
|
|
280
|
+
return client;
|
|
281
|
+
}).finally(() => {
|
|
282
|
+
if (pendingOAuthConnections.get(cacheKey) === promise) pendingOAuthConnections.delete(cacheKey);
|
|
266
283
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
});
|
|
272
|
-
pendingOAuthConnections.set(cacheKey, promise);
|
|
273
|
-
registerMCPConnectionScopePending(promise);
|
|
274
|
-
return promise;
|
|
284
|
+
pendingOAuthConnections.set(cacheKey, promise);
|
|
285
|
+
registerMCPConnectionScopePending(promise);
|
|
286
|
+
return promise;
|
|
287
|
+
}
|
|
275
288
|
}
|
|
276
289
|
async function withCachedOAuthConnection(options, label, fn) {
|
|
277
|
-
|
|
290
|
+
options = { ...options, customHeaders: withAmbientIdentityHeaders(options.customHeaders) };
|
|
291
|
+
return runWithMCPCallContext(
|
|
292
|
+
callContextFor(options.customHeaders, options.requestTimeoutMs),
|
|
293
|
+
() => withCachedOAuthConnectionImpl(options, label, fn)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
async function withCachedOAuthConnectionImpl(options, label, fn) {
|
|
297
|
+
const guardedConnection = options.fetchFn !== void 0;
|
|
278
298
|
if (guardedConnection && currentMCPConnectionScopeKey() === void 0) {
|
|
279
299
|
const { client } = await connectMCP(options);
|
|
280
300
|
let succeeded = false;
|
|
281
301
|
try {
|
|
282
|
-
const result = await fn(client);
|
|
302
|
+
const result = await runCallPhase(options.signal, () => fn(client));
|
|
283
303
|
succeeded = true;
|
|
284
304
|
return result;
|
|
285
305
|
} finally {
|
|
@@ -293,13 +313,11 @@ async function withCachedOAuthConnection(options, label, fn) {
|
|
|
293
313
|
options.signingContext?.cacheKey,
|
|
294
314
|
options.customHeaders,
|
|
295
315
|
options.fetchFn,
|
|
296
|
-
options.signal,
|
|
297
|
-
options.requestTimeoutMs,
|
|
298
316
|
options.allowPrivateIp
|
|
299
317
|
);
|
|
300
318
|
const mcpClient = await getOrCreateOAuthConnection(cacheKey, options);
|
|
301
319
|
try {
|
|
302
|
-
return await fn(mcpClient);
|
|
320
|
+
return await trackConnectionUse(mcpClient, () => runCallPhase(options.signal, () => fn(mcpClient)));
|
|
303
321
|
} catch (error) {
|
|
304
322
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
305
323
|
options.debugLogs.push({
|
|
@@ -308,52 +326,38 @@ async function withCachedOAuthConnection(options, label, fn) {
|
|
|
308
326
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
309
327
|
error
|
|
310
328
|
});
|
|
329
|
+
if (isAbortOrTimeoutError(error)) throw error;
|
|
311
330
|
if (is401Error(error)) {
|
|
312
|
-
oauthConnectionCache.delete(cacheKey);
|
|
313
|
-
try {
|
|
314
|
-
await closeMCPClient(mcpClient, false);
|
|
315
|
-
} catch {
|
|
316
|
-
}
|
|
317
331
|
options.debugLogs.push({
|
|
318
332
|
type: "warning",
|
|
319
333
|
message: `MCP: OAuth authentication issue detected for ${label}; evicted cached connection`,
|
|
320
334
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
321
335
|
});
|
|
322
|
-
throw error;
|
|
323
|
-
}
|
|
324
|
-
if (isAbortOrTimeoutError(error)) {
|
|
325
|
-
oauthConnectionCache.delete(cacheKey);
|
|
326
|
-
try {
|
|
327
|
-
await closeMCPClient(mcpClient, false);
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
if (httpStatusOf(error) === 404) {
|
|
333
|
-
oauthConnectionCache.delete(cacheKey);
|
|
334
|
-
try {
|
|
335
|
-
await closeMCPClient(mcpClient, false);
|
|
336
|
-
} catch {
|
|
337
|
-
}
|
|
338
|
-
throw error;
|
|
339
|
-
}
|
|
340
|
-
oauthConnectionCache.delete(cacheKey);
|
|
341
|
-
try {
|
|
342
|
-
await closeMCPClient(mcpClient, false);
|
|
343
|
-
} catch {
|
|
344
336
|
}
|
|
337
|
+
await retireLegacyConnection(oauthConnectionCache, cacheKey, mcpClient);
|
|
345
338
|
throw error;
|
|
346
339
|
}
|
|
347
340
|
}
|
|
348
341
|
async function withCachedConnection(agentUrl, authToken, authHeaders, debugLogs, label, fn, transportFetch, requestOptions = {}) {
|
|
342
|
+
authHeaders = withAmbientIdentityHeaders(authHeaders);
|
|
343
|
+
return runWithMCPCallContext(
|
|
344
|
+
callContextFor(authHeaders, requestOptions.requestTimeoutMs),
|
|
345
|
+
() => withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugLogs, label, fn, transportFetch, requestOptions)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
async function withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugLogs, label, fn, transportFetch, requestOptions) {
|
|
349
349
|
const signingContext = signingContextStorage.getStore();
|
|
350
350
|
const baseUrl = new URL(agentUrl);
|
|
351
|
-
const guardedConnection = transportFetch !== void 0
|
|
351
|
+
const guardedConnection = transportFetch !== void 0;
|
|
352
352
|
if (guardedConnection && currentMCPConnectionScopeKey() === void 0) {
|
|
353
353
|
const client = await connectMCPWithFallback(baseUrl, authHeaders, debugLogs, label, transportFetch, requestOptions);
|
|
354
354
|
let succeeded = false;
|
|
355
355
|
try {
|
|
356
|
-
const result = await withAbortSignal(
|
|
356
|
+
const result = await withAbortSignal(
|
|
357
|
+
[requestOptions.signal],
|
|
358
|
+
void 0,
|
|
359
|
+
() => runCallPhase(requestOptions.signal, () => fn(client))
|
|
360
|
+
);
|
|
357
361
|
succeeded = true;
|
|
358
362
|
return result;
|
|
359
363
|
} finally {
|
|
@@ -367,8 +371,6 @@ async function withCachedConnection(agentUrl, authToken, authHeaders, debugLogs,
|
|
|
367
371
|
signingContext?.cacheKey,
|
|
368
372
|
authHeaders,
|
|
369
373
|
transportFetch,
|
|
370
|
-
requestOptions.signal,
|
|
371
|
-
requestOptions.requestTimeoutMs,
|
|
372
374
|
requestOptions.allowPrivateIp
|
|
373
375
|
);
|
|
374
376
|
const mcpClient = await getOrCreateConnection(
|
|
@@ -381,7 +383,7 @@ async function withCachedConnection(agentUrl, authToken, authHeaders, debugLogs,
|
|
|
381
383
|
requestOptions
|
|
382
384
|
);
|
|
383
385
|
try {
|
|
384
|
-
return await fn(mcpClient);
|
|
386
|
+
return await trackConnectionUse(mcpClient, () => runCallPhase(requestOptions.signal, () => fn(mcpClient)));
|
|
385
387
|
} catch (error) {
|
|
386
388
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
387
389
|
debugLogs.push({
|
|
@@ -390,48 +392,63 @@ async function withCachedConnection(agentUrl, authToken, authHeaders, debugLogs,
|
|
|
390
392
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
391
393
|
error
|
|
392
394
|
});
|
|
395
|
+
if (isAbortOrTimeoutError(error)) throw error;
|
|
393
396
|
if (is401Error(error)) {
|
|
394
|
-
connectionCache.delete(cacheKey);
|
|
395
|
-
try {
|
|
396
|
-
await closeMCPClient(mcpClient, false);
|
|
397
|
-
} catch {
|
|
398
|
-
}
|
|
399
397
|
debugLogs.push({
|
|
400
398
|
type: "warning",
|
|
401
399
|
message: `MCP: Authentication issue detected for ${label} - headers may not be reaching server`,
|
|
402
400
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
403
401
|
});
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
if (isAbortOrTimeoutError(error)) {
|
|
407
|
-
connectionCache.delete(cacheKey);
|
|
408
|
-
try {
|
|
409
|
-
await closeMCPClient(mcpClient, false);
|
|
410
|
-
} catch {
|
|
411
|
-
}
|
|
412
|
-
throw error;
|
|
413
|
-
}
|
|
414
|
-
if (httpStatusOf(error) === 404) {
|
|
415
|
-
connectionCache.delete(cacheKey);
|
|
416
|
-
try {
|
|
417
|
-
await closeMCPClient(mcpClient, false);
|
|
418
|
-
} catch {
|
|
419
|
-
}
|
|
402
|
+
} else if (httpStatusOf(error) === 404) {
|
|
420
403
|
debugLogs.push({
|
|
421
404
|
type: "warning",
|
|
422
405
|
message: `MCP: Session not found for ${label}; evicted cached connection without retry`,
|
|
423
406
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
424
407
|
});
|
|
425
|
-
throw error;
|
|
426
|
-
}
|
|
427
|
-
connectionCache.delete(cacheKey);
|
|
428
|
-
try {
|
|
429
|
-
await closeMCPClient(mcpClient, false);
|
|
430
|
-
} catch {
|
|
431
408
|
}
|
|
409
|
+
await retireLegacyConnection(connectionCache, cacheKey, mcpClient);
|
|
432
410
|
throw error;
|
|
433
411
|
}
|
|
434
412
|
}
|
|
413
|
+
async function withScopedLegacyConnection(options, label, fn) {
|
|
414
|
+
if (currentMCPConnectionScopeKey() === void 0) return void 0;
|
|
415
|
+
const debugLogs = options.debugLogs ?? [];
|
|
416
|
+
if (options.authProvider) {
|
|
417
|
+
return {
|
|
418
|
+
value: await withCachedOAuthConnection({ ...options, authProvider: options.authProvider, debugLogs }, label, fn)
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const authHeaders = createMCPRequestHeaders(options.customHeaders, options.authToken);
|
|
422
|
+
return {
|
|
423
|
+
value: await withCachedConnection(
|
|
424
|
+
options.agentUrl,
|
|
425
|
+
options.authToken,
|
|
426
|
+
authHeaders,
|
|
427
|
+
debugLogs,
|
|
428
|
+
label,
|
|
429
|
+
fn,
|
|
430
|
+
options.fetchFn,
|
|
431
|
+
{
|
|
432
|
+
signal: options.signal,
|
|
433
|
+
requestTimeoutMs: options.requestTimeoutMs,
|
|
434
|
+
allowPrivateIp: options.allowPrivateIp
|
|
435
|
+
}
|
|
436
|
+
)
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function callContextFor(headers, requestTimeoutMs) {
|
|
440
|
+
const { perRequest } = splitConnectionHeaders(headers);
|
|
441
|
+
const timeoutMs = resolveRequestTimeoutMs(requestTimeoutMs);
|
|
442
|
+
return {
|
|
443
|
+
...Object.keys(perRequest).length > 0 && { headers: perRequest },
|
|
444
|
+
...timeoutMs !== void 0 && { requestTimeoutMs: timeoutMs }
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
async function retireLegacyConnection(cache, cacheKey, client) {
|
|
448
|
+
if (cache.get(cacheKey) === client) cache.delete(cacheKey);
|
|
449
|
+
await closeWhenIdle(client, () => closeMCPClient(client, false)).catch(() => {
|
|
450
|
+
});
|
|
451
|
+
}
|
|
435
452
|
function httpStatusOf(error, depth = 0) {
|
|
436
453
|
if (!error || typeof error !== "object" || depth > 4) return void 0;
|
|
437
454
|
const candidate = error;
|
|
@@ -441,6 +458,7 @@ function httpStatusOf(error, depth = 0) {
|
|
|
441
458
|
return httpStatusOf(candidate.cause, depth + 1);
|
|
442
459
|
}
|
|
443
460
|
async function connectMCPWithFallback(url, authHeaders, debugLogs = [], label = "connection", transportFetch, requestOptions = {}) {
|
|
461
|
+
authHeaders = withAmbientIdentityHeaders(authHeaders);
|
|
444
462
|
return withSpan(
|
|
445
463
|
"adcp.mcp.connect",
|
|
446
464
|
{
|
|
@@ -463,11 +481,15 @@ async function connectMCPWithFallbackImpl(url, authHeaders, debugLogs = [], labe
|
|
|
463
481
|
trustedFetchFn: transportFetch,
|
|
464
482
|
allowPrivateIp: requestOptions.allowPrivateIp
|
|
465
483
|
});
|
|
466
|
-
const networkFetch = (input, init) =>
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
484
|
+
const networkFetch = (input, init) => (
|
|
485
|
+
// Cancellation stays linked for the entire response-body lifetime, through
|
|
486
|
+
// `init.signal`: the v1 transport does not forward a request's own signal, so
|
|
487
|
+
// the active call's signal is linked to that call's POST at the outermost
|
|
488
|
+
// transport wrapper (aborting one call cancels its HTTP request without
|
|
489
|
+
// closing a session other calls share). The background GET/SSE listener
|
|
490
|
+
// never carries a call signal.
|
|
491
|
+
rawNetworkFetch(input, { ...init, signal: init?.signal ?? void 0 })
|
|
492
|
+
);
|
|
471
493
|
const sizeLimited = wrapFetchWithSizeLimit(networkFetch);
|
|
472
494
|
const diagnosticFetch = wrapFetchWithTransportDiagnostics(sizeLimited);
|
|
473
495
|
const baseFetch = signingContext ? buildAgentSigningFetch({
|
|
@@ -477,8 +499,8 @@ async function connectMCPWithFallbackImpl(url, authHeaders, debugLogs = [], labe
|
|
|
477
499
|
adcpVersion: signingContext.adcpVersion
|
|
478
500
|
}) : diagnosticFetch;
|
|
479
501
|
const transportOptions = {
|
|
480
|
-
requestInit: { headers: authHeaders, redirect: "manual" },
|
|
481
|
-
fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(baseFetch))
|
|
502
|
+
requestInit: { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" },
|
|
503
|
+
fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(baseFetch, splitConnectionHeaders(authHeaders).perRequest))
|
|
482
504
|
};
|
|
483
505
|
let failedClient;
|
|
484
506
|
try {
|
|
@@ -572,8 +594,10 @@ async function connectMCPWithFallbackImpl(url, authHeaders, debugLogs = [], labe
|
|
|
572
594
|
try {
|
|
573
595
|
await client.connect(
|
|
574
596
|
new SSEClientTransport(url, {
|
|
575
|
-
requestInit: { headers: authHeaders, redirect: "manual" },
|
|
576
|
-
fetch: wrapFetchWithCapture(
|
|
597
|
+
requestInit: { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" },
|
|
598
|
+
fetch: wrapFetchWithCapture(
|
|
599
|
+
withPerRequestTraceHeaders(baseFetch, splitConnectionHeaders(authHeaders).perRequest)
|
|
600
|
+
)
|
|
577
601
|
}),
|
|
578
602
|
mcpRequestOptions
|
|
579
603
|
);
|
|
@@ -720,11 +744,11 @@ async function connectMCP(options) {
|
|
|
720
744
|
return normalized !== "authorization" && normalized !== "x-adcp-auth";
|
|
721
745
|
})
|
|
722
746
|
) : customHeaders;
|
|
723
|
-
const authHeaders = createMCPRequestHeaders(filteredCustomHeaders, authToken);
|
|
747
|
+
const authHeaders = withAmbientIdentityHeaders(createMCPRequestHeaders(filteredCustomHeaders, authToken));
|
|
724
748
|
const hasNonAcceptCustomHeaders = Object.keys(filteredCustomHeaders ?? {}).some(
|
|
725
749
|
(key) => key.toLowerCase() !== "accept"
|
|
726
750
|
);
|
|
727
|
-
transportOptions.requestInit = { headers: authHeaders, redirect: "manual" };
|
|
751
|
+
transportOptions.requestInit = { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" };
|
|
728
752
|
if (authProvider) {
|
|
729
753
|
transportOptions.authProvider = authProvider;
|
|
730
754
|
debugLogs.push({
|
|
@@ -745,18 +769,27 @@ async function connectMCP(options) {
|
|
|
745
769
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
746
770
|
});
|
|
747
771
|
}
|
|
748
|
-
const requestTimeoutMs = resolveRequestTimeoutMs(configuredRequestTimeoutMs);
|
|
749
772
|
const clientRequestTimeoutMs = resolveClientRequestTimeoutMs(configuredRequestTimeoutMs);
|
|
773
|
+
const directRequestTimeoutMs = resolveRequestTimeoutMs(configuredRequestTimeoutMs);
|
|
750
774
|
const requestOptions = {
|
|
751
775
|
...signal && { signal },
|
|
752
776
|
...clientRequestTimeoutMs !== void 0 && { timeout: clientRequestTimeoutMs }
|
|
753
777
|
};
|
|
754
778
|
const rawNetworkFetch = createAgentTransportFetch(agentUrl, { trustedFetchFn: fetchFn, allowPrivateIp });
|
|
755
779
|
const sizeLimited = wrapFetchWithSizeLimit(
|
|
756
|
-
(input, init) =>
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
780
|
+
(input, init) => (
|
|
781
|
+
// Inside a call context the deadline is that call's; a direct caller who
|
|
782
|
+
// holds the returned client keeps the timeout configured on connect. The
|
|
783
|
+
// call's own signal is already linked into `init.signal` for the whole
|
|
784
|
+
// response body, so aborting one call cancels its streamed POST only.
|
|
785
|
+
withAbortSignal(
|
|
786
|
+
[init?.signal],
|
|
787
|
+
requestTimeoutFor(init, directRequestTimeoutMs),
|
|
788
|
+
(deadline) => rawNetworkFetch(input, {
|
|
789
|
+
...init,
|
|
790
|
+
signal: init?.signal && deadline ? AbortSignal.any([init.signal, deadline]) : deadline ?? init?.signal
|
|
791
|
+
})
|
|
792
|
+
)
|
|
760
793
|
)
|
|
761
794
|
);
|
|
762
795
|
const diagnosticFetch = wrapFetchWithTransportDiagnostics(sizeLimited);
|
|
@@ -766,7 +799,9 @@ async function connectMCP(options) {
|
|
|
766
799
|
getCapability: signingContext.getCapability,
|
|
767
800
|
adcpVersion: signingContext.adcpVersion
|
|
768
801
|
}) : diagnosticFetch;
|
|
769
|
-
transportOptions.fetch = wrapFetchWithCapture(
|
|
802
|
+
transportOptions.fetch = wrapFetchWithCapture(
|
|
803
|
+
withPerRequestTraceHeaders(signedFetch, splitConnectionHeaders(authHeaders).perRequest)
|
|
804
|
+
);
|
|
770
805
|
const transport = new StreamableHTTPClientTransport(baseUrl, transportOptions);
|
|
771
806
|
try {
|
|
772
807
|
await mcpClient.connect(transport, requestOptions);
|
|
@@ -889,5 +924,6 @@ export {
|
|
|
889
924
|
closeOAuthConnections,
|
|
890
925
|
connectMCP,
|
|
891
926
|
connectMCPWithFallback,
|
|
892
|
-
withCachedConnection
|
|
927
|
+
withCachedConnection,
|
|
928
|
+
withScopedLegacyConnection
|
|
893
929
|
};
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle events for one transport request.
|
|
3
|
+
*
|
|
4
|
+
* - `request_started`: the request is about to be sent.
|
|
5
|
+
* - `response_received`: response **headers** arrived. For captured bodies,
|
|
6
|
+
* dispatch waits for the bounded preview. Its `durationMs` is time to
|
|
7
|
+
* headers, not time to completion; it does not mean the reply finished.
|
|
8
|
+
* - `response_completed`: the caller finished with a response body that was not
|
|
9
|
+
* captured (SSE, no finite declared length, non-text, or over the capture
|
|
10
|
+
* limit). Emitted at most once, with an `outcome`, total `bytes` and total
|
|
11
|
+
* `durationMs`.
|
|
12
|
+
* - `request_failed`: the request failed before response headers arrived.
|
|
13
|
+
*/
|
|
14
|
+
export type TransportActivityType = 'request_started' | 'response_received' | 'response_completed' | 'request_failed';
|
|
15
|
+
/** How an uncaptured response body finished. */
|
|
16
|
+
export type TransportResponseOutcome = 'ended' | 'errored' | 'aborted' | 'cancelled';
|
|
2
17
|
export interface TransportActivityContext {
|
|
3
18
|
agentId: string;
|
|
4
19
|
protocol: 'mcp' | 'a2a';
|
|
@@ -34,6 +49,23 @@ export interface TransportActivity {
|
|
|
34
49
|
responseHeaders?: Record<string, string>;
|
|
35
50
|
responseBody?: string;
|
|
36
51
|
responseBodyTruncated?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* On `response_received`: `true` when the body is streamed uncaptured, so a
|
|
54
|
+
* `response_completed` event will follow once the caller finishes reading,
|
|
55
|
+
* cancels, or aborts it. The event then means "headers received", not
|
|
56
|
+
* "reply finished".
|
|
57
|
+
*/
|
|
58
|
+
streaming?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* On `response_completed`: how the body ended. `ended` is EOF, `errored` is a
|
|
61
|
+
* stream error, `aborted` is an `AbortSignal` abort (including a cancel after the
|
|
62
|
+
* signal fired) or abort-style error, and `cancelled` is the consumer
|
|
63
|
+
* cancelling the body without an abort, including SDK cleanup after it has
|
|
64
|
+
* delivered a successful MCP result.
|
|
65
|
+
*/
|
|
66
|
+
outcome?: TransportResponseOutcome;
|
|
67
|
+
/** On `response_completed`: body bytes that passed through before the outcome. */
|
|
68
|
+
bytes?: number;
|
|
37
69
|
errorName?: string;
|
|
38
70
|
errorMessage?: string;
|
|
39
71
|
}
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle events for one transport request.
|
|
3
|
+
*
|
|
4
|
+
* - `request_started`: the request is about to be sent.
|
|
5
|
+
* - `response_received`: response **headers** arrived. For captured bodies,
|
|
6
|
+
* dispatch waits for the bounded preview. Its `durationMs` is time to
|
|
7
|
+
* headers, not time to completion; it does not mean the reply finished.
|
|
8
|
+
* - `response_completed`: the caller finished with a response body that was not
|
|
9
|
+
* captured (SSE, no finite declared length, non-text, or over the capture
|
|
10
|
+
* limit). Emitted at most once, with an `outcome`, total `bytes` and total
|
|
11
|
+
* `durationMs`.
|
|
12
|
+
* - `request_failed`: the request failed before response headers arrived.
|
|
13
|
+
*/
|
|
14
|
+
export type TransportActivityType = 'request_started' | 'response_received' | 'response_completed' | 'request_failed';
|
|
15
|
+
/** How an uncaptured response body finished. */
|
|
16
|
+
export type TransportResponseOutcome = 'ended' | 'errored' | 'aborted' | 'cancelled';
|
|
2
17
|
export interface TransportActivityContext {
|
|
3
18
|
agentId: string;
|
|
4
19
|
protocol: 'mcp' | 'a2a';
|
|
@@ -34,6 +49,23 @@ export interface TransportActivity {
|
|
|
34
49
|
responseHeaders?: Record<string, string>;
|
|
35
50
|
responseBody?: string;
|
|
36
51
|
responseBodyTruncated?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* On `response_received`: `true` when the body is streamed uncaptured, so a
|
|
54
|
+
* `response_completed` event will follow once the caller finishes reading,
|
|
55
|
+
* cancels, or aborts it. The event then means "headers received", not
|
|
56
|
+
* "reply finished".
|
|
57
|
+
*/
|
|
58
|
+
streaming?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* On `response_completed`: how the body ended. `ended` is EOF, `errored` is a
|
|
61
|
+
* stream error, `aborted` is an `AbortSignal` abort (including a cancel after the
|
|
62
|
+
* signal fired) or abort-style error, and `cancelled` is the consumer
|
|
63
|
+
* cancelling the body without an abort, including SDK cleanup after it has
|
|
64
|
+
* delivered a successful MCP result.
|
|
65
|
+
*/
|
|
66
|
+
outcome?: TransportResponseOutcome;
|
|
67
|
+
/** On `response_completed`: body bytes that passed through before the outcome. */
|
|
68
|
+
bytes?: number;
|
|
37
69
|
errorName?: string;
|
|
38
70
|
errorMessage?: string;
|
|
39
71
|
}
|