agentfootprint 9.80.0 → 9.82.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/AGENTS.md +20 -0
- package/CHANGELOG.md +167 -0
- package/CLAUDE.md +3 -1
- package/dist/core/runbook/verdicts.js +30 -6
- package/dist/core/runbook/verdicts.js.map +1 -1
- package/dist/esm/core/runbook/types.d.ts +8 -0
- package/dist/esm/core/runbook/verdicts.d.ts +18 -5
- package/dist/esm/core/runbook/verdicts.js +30 -6
- package/dist/esm/core/runbook/verdicts.js.map +1 -1
- package/dist/esm/lib/mcp/connectionRefusals.d.ts +30 -0
- package/dist/esm/lib/mcp/connectionRefusals.js +110 -0
- package/dist/esm/lib/mcp/connectionRefusals.js.map +1 -0
- package/dist/esm/lib/mcp/index.d.ts +3 -2
- package/dist/esm/lib/mcp/index.js +4 -0
- package/dist/esm/lib/mcp/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpClient.d.ts +18 -5
- package/dist/esm/lib/mcp/mcpClient.js +102 -38
- package/dist/esm/lib/mcp/mcpClient.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +45 -13
- package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
- package/dist/esm/lib/mcp/sdkLoadFailure.d.ts +60 -0
- package/dist/esm/lib/mcp/sdkLoadFailure.js +74 -0
- package/dist/esm/lib/mcp/sdkLoadFailure.js.map +1 -0
- package/dist/esm/lib/mcp/throttleRetry.d.ts +20 -1
- package/dist/esm/lib/mcp/throttleRetry.js +20 -1
- package/dist/esm/lib/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/lib/mcp/transportUrl.d.ts +30 -0
- package/dist/esm/lib/mcp/transportUrl.js +71 -0
- package/dist/esm/lib/mcp/transportUrl.js.map +1 -0
- package/dist/esm/lib/mcp/types.d.ts +143 -13
- package/dist/esm/tool-providers/index.d.ts +2 -2
- package/dist/esm/tool-providers/index.js +6 -1
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/lib/mcp/connectionRefusals.js +114 -0
- package/dist/lib/mcp/connectionRefusals.js.map +1 -0
- package/dist/lib/mcp/index.js +6 -1
- package/dist/lib/mcp/index.js.map +1 -1
- package/dist/lib/mcp/mcpClient.js +102 -38
- package/dist/lib/mcp/mcpClient.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +45 -13
- package/dist/lib/mcp/mcpServe.js.map +1 -1
- package/dist/lib/mcp/sdkLoadFailure.js +78 -0
- package/dist/lib/mcp/sdkLoadFailure.js.map +1 -0
- package/dist/lib/mcp/throttleRetry.js +20 -1
- package/dist/lib/mcp/throttleRetry.js.map +1 -1
- package/dist/lib/mcp/transportUrl.js +75 -0
- package/dist/lib/mcp/transportUrl.js.map +1 -0
- package/dist/tool-providers/index.js +6 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/types/core/runbook/types.d.ts +8 -0
- package/dist/types/core/runbook/types.d.ts.map +1 -1
- package/dist/types/core/runbook/verdicts.d.ts +18 -5
- package/dist/types/core/runbook/verdicts.d.ts.map +1 -1
- package/dist/types/lib/mcp/connectionRefusals.d.ts +31 -0
- package/dist/types/lib/mcp/connectionRefusals.d.ts.map +1 -0
- package/dist/types/lib/mcp/index.d.ts +3 -2
- package/dist/types/lib/mcp/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpClient.d.ts +18 -5
- package/dist/types/lib/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
- package/dist/types/lib/mcp/sdkLoadFailure.d.ts +61 -0
- package/dist/types/lib/mcp/sdkLoadFailure.d.ts.map +1 -0
- package/dist/types/lib/mcp/throttleRetry.d.ts +20 -1
- package/dist/types/lib/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/lib/mcp/transportUrl.d.ts +31 -0
- package/dist/types/lib/mcp/transportUrl.d.ts.map +1 -0
- package/dist/types/lib/mcp/types.d.ts +143 -13
- package/dist/types/lib/mcp/types.d.ts.map +1 -1
- package/dist/types/tool-providers/index.d.ts +2 -2
- package/dist/types/tool-providers/index.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -102,9 +102,28 @@ export type RetryOnThrottle = boolean | ThrottleRetryOptions;
|
|
|
102
102
|
* so a transport that passed no custom fetch keeps passing none and its
|
|
103
103
|
* behaviour is byte-identical to before this existed.
|
|
104
104
|
*
|
|
105
|
+
* ── Why this is public ───────────────────────────────────────────────────────
|
|
106
|
+
* `mcpClient({ transport })` applies it for you, ON by default. `mcpClient({
|
|
107
|
+
* connection })` cannot: the library builds no transport on that arm, so there
|
|
108
|
+
* is no `fetch` of its own to wrap — and a browser consumer, who is the main
|
|
109
|
+
* reason that arm exists, would silently lose the 429 handling Node gets for
|
|
110
|
+
* free. That asymmetry is invisible from the outside, which is why the answer
|
|
111
|
+
* is to hand over the same implementation rather than to document the gap:
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { retryingFetch } from 'agentfootprint/providers';
|
|
115
|
+
* import { StreamableHTTPClientTransport }
|
|
116
|
+
* from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
117
|
+
*
|
|
118
|
+
* const transport = new StreamableHTTPClientTransport(new URL('/mcp', location.href), {
|
|
119
|
+
* fetch: retryingFetch(undefined, { maxAttempts: 5 }),
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
105
123
|
* @param inner the fetch to wrap. `undefined` means the global `fetch`,
|
|
106
124
|
* resolved at CALL time so a later polyfill still wins.
|
|
107
|
-
* @
|
|
125
|
+
* @param config `true` / `undefined` for the defaults, `false` to get `inner`
|
|
126
|
+
* back unchanged, or an object to tune the ceilings.
|
|
108
127
|
*/
|
|
109
128
|
export declare function retryingFetch(inner: ThrottleFetch | undefined, config: RetryOnThrottle | undefined): ThrottleFetch | undefined;
|
|
110
129
|
/**
|
|
@@ -63,9 +63,28 @@ function resolveConfig(config) {
|
|
|
63
63
|
* so a transport that passed no custom fetch keeps passing none and its
|
|
64
64
|
* behaviour is byte-identical to before this existed.
|
|
65
65
|
*
|
|
66
|
+
* ── Why this is public ───────────────────────────────────────────────────────
|
|
67
|
+
* `mcpClient({ transport })` applies it for you, ON by default. `mcpClient({
|
|
68
|
+
* connection })` cannot: the library builds no transport on that arm, so there
|
|
69
|
+
* is no `fetch` of its own to wrap — and a browser consumer, who is the main
|
|
70
|
+
* reason that arm exists, would silently lose the 429 handling Node gets for
|
|
71
|
+
* free. That asymmetry is invisible from the outside, which is why the answer
|
|
72
|
+
* is to hand over the same implementation rather than to document the gap:
|
|
73
|
+
*
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { retryingFetch } from 'agentfootprint/providers';
|
|
76
|
+
* import { StreamableHTTPClientTransport }
|
|
77
|
+
* from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
78
|
+
*
|
|
79
|
+
* const transport = new StreamableHTTPClientTransport(new URL('/mcp', location.href), {
|
|
80
|
+
* fetch: retryingFetch(undefined, { maxAttempts: 5 }),
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
66
84
|
* @param inner the fetch to wrap. `undefined` means the global `fetch`,
|
|
67
85
|
* resolved at CALL time so a later polyfill still wins.
|
|
68
|
-
* @
|
|
86
|
+
* @param config `true` / `undefined` for the defaults, `false` to get `inner`
|
|
87
|
+
* back unchanged, or an object to tune the ceilings.
|
|
69
88
|
*/
|
|
70
89
|
export function retryingFetch(inner, config) {
|
|
71
90
|
const resolved = resolveConfig(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttleRetry.js","sourceRoot":"","sources":["../../../../src/lib/mcp/throttleRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAgEH,wEAAwE;AAExE,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACnC,2DAA2D;AAC3D,MAAM,eAAe,GAAG,GAAG,CAAC;AAQ5B,+EAA+E;AAC/E,SAAS,aAAa,CAAC,MAAmC;IACxD,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,IAAI,GAAyB,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzF,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,IAAI,oBAAoB,CAAC;QAClE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,IAAI,mBAAmB,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,wEAAwE;AAExE
|
|
1
|
+
{"version":3,"file":"throttleRetry.js","sourceRoot":"","sources":["../../../../src/lib/mcp/throttleRetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transportUrl — read `transport.url` the way the runtime it is running in
|
|
3
|
+
* would read it.
|
|
4
|
+
*
|
|
5
|
+
* ── Why ──────────────────────────────────────────────────────────────────────
|
|
6
|
+
* `new URL('/py/mcp')` throws `TypeError: Invalid URL`. In Node that is the
|
|
7
|
+
* right answer: there is no document, so there is no base, and a path on its
|
|
8
|
+
* own names nothing. In a browser it is the wrong answer twice over — the page
|
|
9
|
+
* HAS a base, and `/py/mcp` is the single most ordinary way to name a sidecar
|
|
10
|
+
* behind the same origin (which is also how you avoid a CORS preflight
|
|
11
|
+
* entirely). Before this, a browser consumer's first attempt died on a
|
|
12
|
+
* `TypeError` from deep inside the transport constructor, with nothing in the
|
|
13
|
+
* message naming the URL or the fix.
|
|
14
|
+
*
|
|
15
|
+
* ── The rule ─────────────────────────────────────────────────────────────────
|
|
16
|
+
* An ABSOLUTE url takes the identical first branch it always took, so every
|
|
17
|
+
* existing caller is byte-identical. A relative one resolves against
|
|
18
|
+
* `globalThis.location.href` when there is one. With neither, the refusal says
|
|
19
|
+
* which of the two worlds it is in, because "Invalid URL" does not.
|
|
20
|
+
*
|
|
21
|
+
* Pattern: pure function. Role: Layer-3 tool transport.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a transport URL, honouring a document base when the runtime has one.
|
|
25
|
+
*
|
|
26
|
+
* @param raw the `url` from an `http` or `gateway` transport descriptor
|
|
27
|
+
* @param caller the function to name in the refusal, e.g. `'mcpClient'`
|
|
28
|
+
* @throws when `raw` is neither absolute nor resolvable against a base
|
|
29
|
+
*/
|
|
30
|
+
export declare function transportUrl(raw: string, caller: string): URL;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transportUrl — read `transport.url` the way the runtime it is running in
|
|
3
|
+
* would read it.
|
|
4
|
+
*
|
|
5
|
+
* ── Why ──────────────────────────────────────────────────────────────────────
|
|
6
|
+
* `new URL('/py/mcp')` throws `TypeError: Invalid URL`. In Node that is the
|
|
7
|
+
* right answer: there is no document, so there is no base, and a path on its
|
|
8
|
+
* own names nothing. In a browser it is the wrong answer twice over — the page
|
|
9
|
+
* HAS a base, and `/py/mcp` is the single most ordinary way to name a sidecar
|
|
10
|
+
* behind the same origin (which is also how you avoid a CORS preflight
|
|
11
|
+
* entirely). Before this, a browser consumer's first attempt died on a
|
|
12
|
+
* `TypeError` from deep inside the transport constructor, with nothing in the
|
|
13
|
+
* message naming the URL or the fix.
|
|
14
|
+
*
|
|
15
|
+
* ── The rule ─────────────────────────────────────────────────────────────────
|
|
16
|
+
* An ABSOLUTE url takes the identical first branch it always took, so every
|
|
17
|
+
* existing caller is byte-identical. A relative one resolves against
|
|
18
|
+
* `globalThis.location.href` when there is one. With neither, the refusal says
|
|
19
|
+
* which of the two worlds it is in, because "Invalid URL" does not.
|
|
20
|
+
*
|
|
21
|
+
* Pattern: pure function. Role: Layer-3 tool transport.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a transport URL, honouring a document base when the runtime has one.
|
|
25
|
+
*
|
|
26
|
+
* @param raw the `url` from an `http` or `gateway` transport descriptor
|
|
27
|
+
* @param caller the function to name in the refusal, e.g. `'mcpClient'`
|
|
28
|
+
* @throws when `raw` is neither absolute nor resolvable against a base
|
|
29
|
+
*/
|
|
30
|
+
export function transportUrl(raw, caller) {
|
|
31
|
+
try {
|
|
32
|
+
return new URL(raw);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Not absolute. A browser can still resolve it; Node cannot.
|
|
36
|
+
}
|
|
37
|
+
const base = documentBase();
|
|
38
|
+
if (base !== undefined) {
|
|
39
|
+
try {
|
|
40
|
+
return new URL(raw, base);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// A base existed and still did not help — fall through to the refusal,
|
|
44
|
+
// which names both halves rather than blaming the url alone.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`${caller}: transport.url ${JSON.stringify(raw)} is not an absolute URL, and ` +
|
|
48
|
+
`${base === undefined
|
|
49
|
+
? 'this runtime has no document base to resolve it against (Node, a worker, a test)'
|
|
50
|
+
: `it does not resolve against the document base ${JSON.stringify(base)}`}. ` +
|
|
51
|
+
'Pass an absolute URL (for example `http://127.0.0.1:5230/mcp`); a path like ' +
|
|
52
|
+
'`/mcp` only resolves in a browser, against the page it was loaded from.');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The page's own URL, when there is a page.
|
|
56
|
+
*
|
|
57
|
+
* Read through `globalThis` and guarded, because every access here is on a
|
|
58
|
+
* host object this library does not own: `location` is absent in Node, present
|
|
59
|
+
* but href-less in some worker and test doubles, and a getter that throws in a
|
|
60
|
+
* sandboxed frame.
|
|
61
|
+
*/
|
|
62
|
+
function documentBase() {
|
|
63
|
+
try {
|
|
64
|
+
const href = globalThis.location?.href;
|
|
65
|
+
return typeof href === 'string' && href.length > 0 ? href : undefined;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=transportUrl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportUrl.js","sourceRoot":"","sources":["../../../../src/lib/mcp/transportUrl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,MAAc;IACtD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,6DAA6D;QAC/D,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,GAAG,MAAM,mBAAmB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,+BAA+B;QAC5E,GACE,IAAI,KAAK,SAAS;YAChB,CAAC,CAAC,kFAAkF;YACpF,CAAC,CAAC,iDAAiD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAC3E,IAAI;QACJ,8EAA8E;QAC9E,yEAAyE,CAC5E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,IAAI,GAAI,UAAgD,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC9E,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -199,6 +199,25 @@ export interface McpClientOptions {
|
|
|
199
199
|
* Ignored for `stdio`, which has no HTTP status to read.
|
|
200
200
|
*/
|
|
201
201
|
readonly retryOnThrottle?: RetryOnThrottle;
|
|
202
|
+
/**
|
|
203
|
+
* Pre-resolved SDK modules. Give these and the library never touches its Node
|
|
204
|
+
* `require` loader — which is the whole reason a browser bundle can now speak
|
|
205
|
+
* MCP over `http`.
|
|
206
|
+
*
|
|
207
|
+
* Everything else keeps working, because the library still builds the
|
|
208
|
+
* transport: gateway vending, `retryOnThrottle`, `headers`, your own `fetch`,
|
|
209
|
+
* `_meta` ingestion. Omit it and the loader runs exactly as it always has.
|
|
210
|
+
*
|
|
211
|
+
* Ignored for `transport: 'stdio'`, which spawns a subprocess and therefore
|
|
212
|
+
* cannot run in a browser at all — that branch keeps loading
|
|
213
|
+
* `client/stdio.js` through the Node loader, which is also what keeps the
|
|
214
|
+
* SDK's only Node-bound client module off a browser's module graph.
|
|
215
|
+
*
|
|
216
|
+
* @see McpSdk for the two static imports that produce it.
|
|
217
|
+
*/
|
|
218
|
+
readonly sdk?: McpSdk;
|
|
219
|
+
/** @see McpConnectionOptions — never set on this arm. */
|
|
220
|
+
readonly connection?: undefined;
|
|
202
221
|
/**
|
|
203
222
|
* @internal Pre-built SDK client for tests. Skips SDK import +
|
|
204
223
|
* transport construction. Same convention as `AnthropicProvider._client`.
|
|
@@ -210,6 +229,45 @@ export interface McpClientOptions {
|
|
|
210
229
|
*/
|
|
211
230
|
readonly _client?: McpSdkClient;
|
|
212
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* The other arm of `mcpClient`: you connected the client, the library adapts it.
|
|
234
|
+
*
|
|
235
|
+
* Reach for this when the library must not construct anything at all — a
|
|
236
|
+
* browser bundle behind a strict CSP, where you need the SDK's own
|
|
237
|
+
* `jsonSchemaValidator` to keep ajv's code generation off the page; or any
|
|
238
|
+
* transport this library has never heard of.
|
|
239
|
+
*
|
|
240
|
+
* The cost is stated rather than hidden: the library builds no transport here,
|
|
241
|
+
* so every option that is consumed INSIDE a transport is refused rather than
|
|
242
|
+
* accepted and ignored. `retryOnThrottle` becomes `retryingFetch` around
|
|
243
|
+
* your own `fetch`; `clientInfo` and `headers` are yours to set when you
|
|
244
|
+
* construct the client. `signal` IS honoured — it rides the SDK's trailing
|
|
245
|
+
* request-options argument, not the transport.
|
|
246
|
+
*/
|
|
247
|
+
export interface McpConnectionOptions {
|
|
248
|
+
/**
|
|
249
|
+
* Logical name for observability + tool-call routing, exactly as on
|
|
250
|
+
* {@link McpClientOptions}. Defaults to `'mcp'`.
|
|
251
|
+
*/
|
|
252
|
+
readonly name?: string;
|
|
253
|
+
/**
|
|
254
|
+
* A connection you already opened. The library never calls `connect()` on it;
|
|
255
|
+
* `close()` on the returned client closes it exactly once.
|
|
256
|
+
*/
|
|
257
|
+
readonly connection: McpConnection;
|
|
258
|
+
/** Abort the list / call paths. Rides the SDK's request options. */
|
|
259
|
+
readonly signal?: AbortSignal;
|
|
260
|
+
/** @see McpClientOptions — never set on this arm. */
|
|
261
|
+
readonly transport?: undefined;
|
|
262
|
+
/** @see McpClientOptions — never set on this arm. */
|
|
263
|
+
readonly sdk?: undefined;
|
|
264
|
+
/** @see McpClientOptions — never set on this arm. */
|
|
265
|
+
readonly clientInfo?: undefined;
|
|
266
|
+
/** @see McpClientOptions — never set on this arm. */
|
|
267
|
+
readonly retryOnThrottle?: undefined;
|
|
268
|
+
/** @internal @see McpClientOptions — never set on this arm. */
|
|
269
|
+
readonly _client?: undefined;
|
|
270
|
+
}
|
|
213
271
|
/**
|
|
214
272
|
* What `mcpClient(opts)` returns. Connect once; call `.tools()` to
|
|
215
273
|
* snapshot the tool list, `.refresh()` to re-list after the server's
|
|
@@ -235,23 +293,30 @@ export interface McpClient {
|
|
|
235
293
|
close(): Promise<void>;
|
|
236
294
|
}
|
|
237
295
|
/**
|
|
238
|
-
*
|
|
239
|
-
* we touch. Defined locally so we can:
|
|
240
|
-
* 1. Inject a mock for tests (`McpClientOptions._client`)
|
|
241
|
-
* 2. Avoid a hard import on `@modelcontextprotocol/sdk` (which is
|
|
242
|
-
* a lazy peer-dep)
|
|
296
|
+
* A live MCP connection you opened and connected yourself.
|
|
243
297
|
*
|
|
244
|
-
*
|
|
298
|
+
* This is the whole contract this library needs from an MCP client: three
|
|
299
|
+
* methods over JSON-RPC. Nothing in it names a vendor, so an SDK `Client`, a
|
|
300
|
+
* hand-written fake, or a future fetch-only transport all satisfy it.
|
|
301
|
+
*
|
|
302
|
+
* Pass one as `mcpClient({ connection })` when the library must not load the
|
|
303
|
+
* SDK itself — a browser bundle, where the Node `require` loader does not
|
|
304
|
+
* exist. You own construction, so you also own the transport's `fetch`, its
|
|
305
|
+
* headers, its auth, and (SDK-specific) its `jsonSchemaValidator`, which is the
|
|
306
|
+
* one way to keep ajv's `new Function` off a page with a strict CSP.
|
|
307
|
+
*
|
|
308
|
+
* What you give up by owning it: this library builds no transport on that arm,
|
|
309
|
+
* so `retryOnThrottle` has nothing to wrap. Wrap your own fetch with
|
|
310
|
+
* `retryingFetch` and the 429 handling comes back.
|
|
245
311
|
*
|
|
246
312
|
* Argument POSITION matters here and is easy to get wrong: the SDK keeps
|
|
247
|
-
* per-request options (`signal`, `timeout`) in a SEPARATE trailing
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
313
|
+
* per-request options (`signal`, `timeout`) in a SEPARATE trailing argument,
|
|
314
|
+
* never inside the JSON-RPC params. A `signal` smuggled into the params object
|
|
315
|
+
* is serialized onto the wire as `{}` and silently fails to cancel anything, so
|
|
316
|
+
* these signatures mirror the SDK's own shape rather than a flattened
|
|
317
|
+
* convenience version of it.
|
|
252
318
|
*/
|
|
253
|
-
export interface
|
|
254
|
-
connect(transport: unknown, options?: McpRequestOptions): Promise<void>;
|
|
319
|
+
export interface McpConnection {
|
|
255
320
|
listTools(params?: undefined, options?: McpRequestOptions): Promise<{
|
|
256
321
|
readonly tools: ReadonlyArray<McpListedTool>;
|
|
257
322
|
}>;
|
|
@@ -263,6 +328,71 @@ export interface McpSdkClient {
|
|
|
263
328
|
resultSchema?: undefined, options?: McpRequestOptions): Promise<McpCallToolResult>;
|
|
264
329
|
close(): Promise<void>;
|
|
265
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* Minimal structural type capturing the parts of the MCP SDK client
|
|
333
|
+
* we touch. Defined locally so we can:
|
|
334
|
+
* 1. Inject a mock for tests (`McpClientOptions._client`)
|
|
335
|
+
* 2. Avoid a hard import on `@modelcontextprotocol/sdk` (which is
|
|
336
|
+
* a lazy peer-dep)
|
|
337
|
+
*
|
|
338
|
+
* The real SDK exports a richer surface; we narrow to what's needed.
|
|
339
|
+
*
|
|
340
|
+
* Member set unchanged since it was introduced: {@link McpConnection} plus the
|
|
341
|
+
* one method the library calls when it opens the connection ITSELF. The split
|
|
342
|
+
* is what lets a caller hand over a client that is already connected without
|
|
343
|
+
* also promising a `connect` this library must never call on it.
|
|
344
|
+
*/
|
|
345
|
+
export interface McpSdkClient extends McpConnection {
|
|
346
|
+
connect(transport: unknown, options?: McpRequestOptions): Promise<void>;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The two `@modelcontextprotocol/sdk` module exports the Streamable HTTP path
|
|
350
|
+
* needs, typed STRUCTURALLY so this declaration never references the optional
|
|
351
|
+
* peer — a consumer without the SDK installed still typechecks.
|
|
352
|
+
*
|
|
353
|
+
* Hand these to `mcpClient({ sdk })` and the library never touches its Node
|
|
354
|
+
* `require` loader, which is what lets a browser bundle speak MCP over `http`.
|
|
355
|
+
* Everything else keeps working, because the library still builds the
|
|
356
|
+
* transport: gateway vending, `retryOnThrottle`, `headers`, your own `fetch`,
|
|
357
|
+
* `_meta` ingestion.
|
|
358
|
+
*
|
|
359
|
+
* Load them yourself with two static imports. The subpaths matter: the SDK's
|
|
360
|
+
* root export `"."` does not resolve (it declares no `dist/esm/index.js`), and
|
|
361
|
+
* `client/stdio.js` is the one client module that imports `node:process` and
|
|
362
|
+
* `node:stream` — importing it is what would drag Node into a browser graph.
|
|
363
|
+
*
|
|
364
|
+
* ```ts
|
|
365
|
+
* import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
366
|
+
* import { StreamableHTTPClientTransport }
|
|
367
|
+
* from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
368
|
+
*
|
|
369
|
+
* const client = await mcpClient({
|
|
370
|
+
* name: 'sidecar',
|
|
371
|
+
* sdk: { Client, StreamableHTTPClientTransport },
|
|
372
|
+
* transport: { transport: 'http', url: '/py/mcp' },
|
|
373
|
+
* });
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
export interface McpSdk {
|
|
377
|
+
readonly Client: new (info: {
|
|
378
|
+
name: string;
|
|
379
|
+
version: string;
|
|
380
|
+
}, options: {
|
|
381
|
+
capabilities: Record<string, unknown>;
|
|
382
|
+
}) => McpSdkClient;
|
|
383
|
+
readonly StreamableHTTPClientTransport: new (url: URL, options?: {
|
|
384
|
+
requestInit?: {
|
|
385
|
+
headers: Record<string, string>;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* The SDK's hook for a custom fetch — how per-request vending AND
|
|
389
|
+
* caller-supplied signing both get in. Typed exactly as the SDK types it,
|
|
390
|
+
* so a function this shim accepts is a function the real transport
|
|
391
|
+
* accepts.
|
|
392
|
+
*/
|
|
393
|
+
fetch?: (url: string | URL, init?: RequestInit) => Promise<Response>;
|
|
394
|
+
}) => unknown;
|
|
395
|
+
}
|
|
266
396
|
/**
|
|
267
397
|
* One entry of a `tools/list` answer, narrowed to what this client reads.
|
|
268
398
|
*
|
|
@@ -51,7 +51,7 @@ export { staticTools } from './staticTools.js';
|
|
|
51
51
|
export { gatedTools } from './gatedTools.js';
|
|
52
52
|
export { skillScopedTools, skillScopedToolsTarget, SKILL_SCOPED_TOOLS_ID_PREFIX, } from './skillScopedTools.js';
|
|
53
53
|
export type { ToolProvider, ToolDispatchContext, ToolGatePredicate } from './types.js';
|
|
54
|
-
export { mcpClient, mcpServe, mockMcpClient, gatewayTransport, GatewayAuthorizationRequiredError, MCP_TOOL_EXTRAS_KEY, } from '../lib/mcp/index.js';
|
|
54
|
+
export { mcpClient, mcpServe, mockMcpClient, gatewayTransport, GatewayAuthorizationRequiredError, MCP_TOOL_EXTRAS_KEY, retryingFetch, } from '../lib/mcp/index.js';
|
|
55
55
|
export { agentCoreGatewayTransport, agentCoreGatewayUrl, gatewaySearchTool, hasGatewaySearch, AGENTCORE_GATEWAY_SEARCH_TOOL, AGENTCORE_POLICY_SESSION_HEADER, AGENTCORE_SIGV4_SERVICE, } from '../adapters/mcp/agentcore.js';
|
|
56
56
|
export type { AgentCoreGatewayTransportOptions, AgentCoreGatewayUrlOptions, } from '../adapters/mcp/agentcore.js';
|
|
57
|
-
export type { GatewayTransportOptions, McpCallToolResult, McpClient, McpClientOptions, McpSdkClient, McpTransport, McpStdioTransport, McpHttpTransport, McpGatewayTransport, MockMcpClientOptions, MockMcpTool, McpServeOptions, McpServeHandle, McpServeTransport, McpStdioServeTransport, McpHttpServeTransport, McpSdkServer, McpToolExtras, } from '../lib/mcp/index.js';
|
|
57
|
+
export type { GatewayTransportOptions, McpCallToolResult, McpClient, McpClientOptions, McpConnection, McpConnectionOptions, McpSdk, McpSdkClient, ThrottleFetch, McpTransport, McpStdioTransport, McpHttpTransport, McpGatewayTransport, MockMcpClientOptions, MockMcpTool, McpServeOptions, McpServeHandle, McpServeTransport, McpStdioServeTransport, McpHttpServeTransport, McpSdkServer, McpToolExtras, } from '../lib/mcp/index.js';
|
|
@@ -60,7 +60,12 @@ export { mcpClient, mcpServe, mockMcpClient, gatewayTransport, GatewayAuthorizat
|
|
|
60
60
|
// The `_meta` key agentfootprint's tool declarations travel under, in both
|
|
61
61
|
// directions (9.71.0). Public so a server this library did not write can
|
|
62
62
|
// speak it, and so a client can read a bag it received.
|
|
63
|
-
MCP_TOOL_EXTRAS_KEY,
|
|
63
|
+
MCP_TOOL_EXTRAS_KEY,
|
|
64
|
+
// The 429 retry `mcpClient({ transport })` applies for you (9.81.0). Public
|
|
65
|
+
// so `mcpClient({ connection })` — the arm a browser takes, where the library
|
|
66
|
+
// builds no transport — can wrap its own `fetch` with the same code rather
|
|
67
|
+
// than quietly doing without it.
|
|
68
|
+
retryingFetch, } from '../lib/mcp/index.js';
|
|
64
69
|
// Reaching an AWS Bedrock AgentCore Gateway (9.66.0). A configuration of
|
|
65
70
|
// `gatewayTransport` plus the four facts that are AgentCore's alone — kept in
|
|
66
71
|
// the vendor's own file so the transport above stays able to say, truthfully,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tool-providers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,gBAAgB;AAChB,kFAAkF;AAClF,kFAAkF;AAClF,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAG/B,uEAAuE;AACvE,wEAAwE;AACxE,0CAA0C;AAC1C,OAAO,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,iCAAiC;AACjC,2EAA2E;AAC3E,yEAAyE;AACzE,wDAAwD;AACxD,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tool-providers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,gBAAgB;AAChB,kFAAkF;AAClF,kFAAkF;AAClF,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAG/B,uEAAuE;AACvE,wEAAwE;AACxE,0CAA0C;AAC1C,OAAO,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,iCAAiC;AACjC,2EAA2E;AAC3E,yEAAyE;AACzE,wDAAwD;AACxD,mBAAmB;AACnB,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,iCAAiC;AACjC,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,yEAAyE;AACzE,8EAA8E;AAC9E,8EAA8E;AAC9E,yCAAyC;AACzC,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,GACxB,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* connectionRefusals — the two arms of `mcpClient` refuse to be mixed, at
|
|
4
|
+
* CONSTRUCTION, in words that name where the behaviour went.
|
|
5
|
+
*
|
|
6
|
+
* ── Why refuse rather than ignore ────────────────────────────────────────────
|
|
7
|
+
* `mcpClient({ connection })` hands over a client somebody else built, so this
|
|
8
|
+
* library builds no transport on that arm — and every option consumed INSIDE a
|
|
9
|
+
* transport therefore has nothing to act on. `retryOnThrottle` is the sharp
|
|
10
|
+
* one: it is ON by default, it is consumed by `retryingFetch` around the
|
|
11
|
+
* transport's `fetch`, and accepting it here would leave a caller holding an
|
|
12
|
+
* option that NAMES a behaviour which no longer happens. A knob that lies about
|
|
13
|
+
* what it does is worse than one that is absent, so these throw.
|
|
14
|
+
*
|
|
15
|
+
* The type union refuses the same combinations at compile time
|
|
16
|
+
* (`McpConnectionOptions` declares each of them `?: undefined`). This is the
|
|
17
|
+
* runtime half, and it is not redundant: excess-property checking does not
|
|
18
|
+
* survive a spread, and JavaScript callers have no compiler at all.
|
|
19
|
+
*
|
|
20
|
+
* Pattern: pure guard. Role: Layer-3 tool integration.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.refuseConflictingOptions = void 0;
|
|
24
|
+
/** The three methods this library calls on a connection. Nothing else. */
|
|
25
|
+
const CONNECTION_METHODS = ['listTools', 'callTool', 'close'];
|
|
26
|
+
/**
|
|
27
|
+
* Refuse a mixed or malformed options object before anything connects.
|
|
28
|
+
*
|
|
29
|
+
* @param opts what the caller passed, before any defaulting
|
|
30
|
+
* @param name the client's logical name, so a multi-server app knows which one
|
|
31
|
+
* @throws naming the two options that cannot travel together, or the member the
|
|
32
|
+
* connection is missing
|
|
33
|
+
*/
|
|
34
|
+
function refuseConflictingOptions(opts, name) {
|
|
35
|
+
const at = `mcpClient[${name}]`;
|
|
36
|
+
// Read through a permissive view on purpose. The union already narrows these
|
|
37
|
+
// combinations away at compile time, so narrowing here would leave the guard
|
|
38
|
+
// reasoning about a shape it exists precisely to disbelieve — an object built
|
|
39
|
+
// by a spread, or by JavaScript.
|
|
40
|
+
const given = opts;
|
|
41
|
+
if (given['connection'] === undefined) {
|
|
42
|
+
if (given['transport'] === undefined && given['_client'] === undefined) {
|
|
43
|
+
throw new Error(`${at}: nothing to connect to. Pass \`transport\` (the library builds the connection) ` +
|
|
44
|
+
'or `connection` (a client you connected yourself).');
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// From here on the caller chose the `connection` arm.
|
|
49
|
+
for (const [option, moved] of BUILT_BY_THE_TRANSPORT) {
|
|
50
|
+
if (given[option] !== undefined) {
|
|
51
|
+
throw new Error(`${at}: \`connection\` and \`${option}\` cannot travel together. ` +
|
|
52
|
+
`A connection you built yourself carries its own transport, and \`${option}\` is ` +
|
|
53
|
+
`consumed inside the transport this library did not build. ${moved}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
assertConnection(given['connection'], at);
|
|
57
|
+
}
|
|
58
|
+
exports.refuseConflictingOptions = refuseConflictingOptions;
|
|
59
|
+
/**
|
|
60
|
+
* The options that only exist because the library builds the transport, each
|
|
61
|
+
* paired with the sentence naming where that behaviour moved to. Ordered so the
|
|
62
|
+
* most surprising loss — throttle retry, which is ON by default — is named
|
|
63
|
+
* first when a caller passes several.
|
|
64
|
+
*/
|
|
65
|
+
const BUILT_BY_THE_TRANSPORT = [
|
|
66
|
+
[
|
|
67
|
+
'retryOnThrottle',
|
|
68
|
+
'Wrap your own `fetch` with `retryingFetch(yourFetch, options)` (exported from ' +
|
|
69
|
+
'`agentfootprint/providers`) and hand THAT to your transport — it is the same ' +
|
|
70
|
+
'implementation, applied where you build it.',
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
'clientInfo',
|
|
74
|
+
'Pass it to the SDK `Client` constructor instead: `new Client(clientInfo, { capabilities: {} })`.',
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
'transport',
|
|
78
|
+
'Drop one of the two: `transport` asks the library to connect, `connection` says it already is.',
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
'sdk',
|
|
82
|
+
'`sdk` exists so the library can build the transport without its Node loader; ' +
|
|
83
|
+
'on this arm you have already built it.',
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
'_client',
|
|
87
|
+
'`_client` is the same idea as `connection` and predates it — pass `connection` alone.',
|
|
88
|
+
],
|
|
89
|
+
];
|
|
90
|
+
/**
|
|
91
|
+
* A connection is only a connection if it can be called.
|
|
92
|
+
*
|
|
93
|
+
* This catches the near-miss people actually make: handing over the TRANSPORT
|
|
94
|
+
* rather than the client. A transport has none of these three methods, and
|
|
95
|
+
* without this check it fails on the first `tools()`, one stack frame deep
|
|
96
|
+
* inside the SDK.
|
|
97
|
+
*
|
|
98
|
+
* The OTHER near-miss — a `Client` that was constructed but never `connect()`ed
|
|
99
|
+
* — cannot be caught here, because it has all three methods. It is named in the
|
|
100
|
+
* message anyway, since it produces the same "my connection does not work" and
|
|
101
|
+
* the SDK's own "Not connected" is the thing to look for.
|
|
102
|
+
*/
|
|
103
|
+
function assertConnection(connection, at) {
|
|
104
|
+
const members = (connection ?? {});
|
|
105
|
+
for (const method of CONNECTION_METHODS) {
|
|
106
|
+
if (typeof members[method] !== 'function') {
|
|
107
|
+
throw new Error(`${at}: \`connection\` has no \`${method}()\`. It must be an MCP client that is ` +
|
|
108
|
+
'already connected, and the likely mistake is passing the TRANSPORT instead of the ' +
|
|
109
|
+
'client. (A `new Client(...)` you never awaited `connect()` on passes this check ' +
|
|
110
|
+
'and fails later with the SDK\'s own "Not connected".)');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=connectionRefusals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionRefusals.js","sourceRoot":"","sources":["../../../src/lib/mcp/connectionRefusals.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAIH,0EAA0E;AAC1E,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAU,CAAC;AAEvE;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CACtC,IAA6C,EAC7C,IAAY;IAEZ,MAAM,EAAE,GAAG,aAAa,IAAI,GAAG,CAAC;IAChC,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,iCAAiC;IACjC,MAAM,KAAK,GAAG,IAAoD,CAAC;IAEnE,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,SAAS,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CACb,GAAG,EAAE,kFAAkF;gBACrF,oDAAoD,CACvD,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,sDAAsD;IACtD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,sBAAsB,EAAE,CAAC;QACrD,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,GAAG,EAAE,0BAA0B,MAAM,6BAA6B;gBAChE,oEAAoE,MAAM,QAAQ;gBAClF,6DAA6D,KAAK,EAAE,CACvE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,gBAAgB,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAhCD,4DAgCC;AAED;;;;;GAKG;AACH,MAAM,sBAAsB,GAExB;IACF;QACE,iBAAiB;QACjB,gFAAgF;YAC9E,+EAA+E;YAC/E,6CAA6C;KAChD;IACD;QACE,YAAY;QACZ,kGAAkG;KACnG;IACD;QACE,WAAW;QACX,gGAAgG;KACjG;IACD;QACE,KAAK;QACL,+EAA+E;YAC7E,wCAAwC;KAC3C;IACD;QACE,SAAS;QACT,uFAAuF;KACxF;CACF,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,SAAS,gBAAgB,CAAC,UAAmB,EAAE,EAAU;IACvD,MAAM,OAAO,GAAG,CAAC,UAAU,IAAI,EAAE,CAAsC,CAAC;IACxE,KAAK,MAAM,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACxC,IAAI,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,GAAG,EAAE,6BAA6B,MAAM,yCAAyC;gBAC/E,oFAAoF;gBACpF,kFAAkF;gBAClF,uDAAuD,CAC1D,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/lib/mcp/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GatewayAuthorizationRequiredError = exports.gatewayTransport = exports.mockMcpClient = exports.MCP_TOOL_EXTRAS_KEY = exports.mcpServe = exports.mcpClient = void 0;
|
|
3
|
+
exports.retryingFetch = exports.GatewayAuthorizationRequiredError = exports.gatewayTransport = exports.mockMcpClient = exports.MCP_TOOL_EXTRAS_KEY = exports.mcpServe = exports.mcpClient = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* MCP — Model Context Protocol, both directions. `mcpClient` connects to
|
|
6
6
|
* someone else's MCP server and registers its tools on your Agent;
|
|
@@ -20,4 +20,9 @@ Object.defineProperty(exports, "mockMcpClient", { enumerable: true, get: functio
|
|
|
20
20
|
var gatewayTransport_js_1 = require("./gatewayTransport.js");
|
|
21
21
|
Object.defineProperty(exports, "gatewayTransport", { enumerable: true, get: function () { return gatewayTransport_js_1.gatewayTransport; } });
|
|
22
22
|
Object.defineProperty(exports, "GatewayAuthorizationRequiredError", { enumerable: true, get: function () { return gatewayTransport_js_1.GatewayAuthorizationRequiredError; } });
|
|
23
|
+
// The 429 handling `mcpClient({ transport })` applies for you — public since
|
|
24
|
+
// 9.81.0 so the `connection` arm, which builds no transport of its own, can
|
|
25
|
+
// apply the SAME implementation instead of silently going without it.
|
|
26
|
+
var throttleRetry_js_1 = require("./throttleRetry.js");
|
|
27
|
+
Object.defineProperty(exports, "retryingFetch", { enumerable: true, get: function () { return throttleRetry_js_1.retryingFetch; } });
|
|
23
28
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/mcp/index.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAClB,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,8EAA8E;AAC9E,0EAA0E;AAC1E,iDAA0E;AAAjE,oHAAA,mBAAmB,OAAA;AAC5B,uDAAgG;AAAvF,iHAAA,aAAa,OAAA;AACtB,6DAI+B;AAH7B,uHAAA,gBAAgB,OAAA;AAChB,wIAAA,iCAAiC,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/mcp/index.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAClB,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,8EAA8E;AAC9E,0EAA0E;AAC1E,iDAA0E;AAAjE,oHAAA,mBAAmB,OAAA;AAC5B,uDAAgG;AAAvF,iHAAA,aAAa,OAAA;AACtB,6DAI+B;AAH7B,uHAAA,gBAAgB,OAAA;AAChB,wIAAA,iCAAiC,OAAA;AAGnC,6EAA6E;AAC7E,4EAA4E;AAC5E,sEAAsE;AACtE,uDAAmD;AAA1C,iHAAA,aAAa,OAAA"}
|