agentfootprint 12.0.1 → 12.2.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 +1 -1
- package/CAPABILITIES.md +3 -0
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js +113 -7
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/session.js +21 -21
- package/dist/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js +79 -5
- package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/core/Agent.js +6 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +4 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +8 -0
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +112 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.js +21 -21
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +81 -7
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/esm/core/Agent.js +6 -0
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +4 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/slots/buildToolsSlot.d.ts +12 -0
- package/dist/esm/core/slots/buildToolsSlot.js +8 -0
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +41 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/identity/types.d.ts +7 -3
- package/dist/esm/identity/types.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/boundedJson.d.ts +14 -7
- package/dist/esm/lib/boundedJson.js +14 -7
- package/dist/esm/lib/boundedJson.js.map +1 -1
- package/dist/esm/mcp/callChecks.d.ts +160 -0
- package/dist/esm/mcp/callChecks.js +237 -0
- package/dist/esm/mcp/callChecks.js.map +1 -0
- package/dist/esm/mcp/callLifetime.js +5 -2
- package/dist/esm/mcp/callLifetime.js.map +1 -1
- package/dist/esm/mcp/clientPort.d.ts +78 -0
- package/dist/esm/mcp/clientPort.js +33 -0
- package/dist/esm/mcp/clientPort.js.map +1 -0
- package/dist/esm/mcp/gatewayTransport.js +13 -3
- package/dist/esm/mcp/gatewayTransport.js.map +1 -1
- package/dist/esm/mcp/index.d.ts +11 -1
- package/dist/esm/mcp/index.js +15 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/listingGenerations.d.ts +54 -0
- package/dist/esm/mcp/listingGenerations.js +75 -0
- package/dist/esm/mcp/listingGenerations.js.map +1 -0
- package/dist/esm/mcp/mcpClient.d.ts +18 -1
- package/dist/esm/mcp/mcpClient.js +302 -57
- package/dist/esm/mcp/mcpClient.js.map +1 -1
- package/dist/esm/mcp/mockMcpClient.js +13 -0
- package/dist/esm/mcp/mockMcpClient.js.map +1 -1
- package/dist/esm/mcp/pool/boundTool.d.ts +58 -0
- package/dist/esm/mcp/pool/boundTool.js +218 -0
- package/dist/esm/mcp/pool/boundTool.js.map +1 -0
- package/dist/esm/mcp/pool/clientSet.d.ts +73 -0
- package/dist/esm/mcp/pool/clientSet.js +152 -0
- package/dist/esm/mcp/pool/clientSet.js.map +1 -0
- package/dist/esm/mcp/pool/definitions.d.ts +103 -0
- package/dist/esm/mcp/pool/definitions.js +168 -0
- package/dist/esm/mcp/pool/definitions.js.map +1 -0
- package/dist/esm/mcp/pool/errors.d.ts +76 -0
- package/dist/esm/mcp/pool/errors.js +91 -0
- package/dist/esm/mcp/pool/errors.js.map +1 -0
- package/dist/esm/mcp/pool/identityKey.d.ts +57 -0
- package/dist/esm/mcp/pool/identityKey.js +94 -0
- package/dist/esm/mcp/pool/identityKey.js.map +1 -0
- package/dist/esm/mcp/pool/lease.d.ts +36 -0
- package/dist/esm/mcp/pool/lease.js +51 -0
- package/dist/esm/mcp/pool/lease.js.map +1 -0
- package/dist/esm/mcp/pool/listTools.d.ts +33 -0
- package/dist/esm/mcp/pool/listTools.js +146 -0
- package/dist/esm/mcp/pool/listTools.js.map +1 -0
- package/dist/esm/mcp/pool/mcpClientPool.d.ts +121 -0
- package/dist/esm/mcp/pool/mcpClientPool.js +151 -0
- package/dist/esm/mcp/pool/mcpClientPool.js.map +1 -0
- package/dist/esm/mcp/pool/options.d.ts +183 -0
- package/dist/esm/mcp/pool/options.js +119 -0
- package/dist/esm/mcp/pool/options.js.map +1 -0
- package/dist/esm/mcp/pool/plan.d.ts +77 -0
- package/dist/esm/mcp/pool/plan.js +134 -0
- package/dist/esm/mcp/pool/plan.js.map +1 -0
- package/dist/esm/mcp/pool/pool.d.ts +307 -0
- package/dist/esm/mcp/pool/pool.js +1071 -0
- package/dist/esm/mcp/pool/pool.js.map +1 -0
- package/dist/esm/mcp/pool/pooledClient.d.ts +93 -0
- package/dist/esm/mcp/pool/pooledClient.js +90 -0
- package/dist/esm/mcp/pool/pooledClient.js.map +1 -0
- package/dist/esm/mcp/pool/record.d.ts +80 -0
- package/dist/esm/mcp/pool/record.js +75 -0
- package/dist/esm/mcp/pool/record.js.map +1 -0
- package/dist/esm/mcp/pool/sessionEnded.d.ts +24 -0
- package/dist/esm/mcp/pool/sessionEnded.js +31 -0
- package/dist/esm/mcp/pool/sessionEnded.js.map +1 -0
- package/dist/esm/mcp/pool/work.d.ts +116 -0
- package/dist/esm/mcp/pool/work.js +213 -0
- package/dist/esm/mcp/pool/work.js.map +1 -0
- package/dist/esm/mcp/requestGuard.d.ts +70 -0
- package/dist/esm/mcp/requestGuard.js +98 -0
- package/dist/esm/mcp/requestGuard.js.map +1 -0
- package/dist/esm/mcp/requestLedger.d.ts +35 -1
- package/dist/esm/mcp/requestLedger.js +76 -3
- package/dist/esm/mcp/requestLedger.js.map +1 -1
- package/dist/esm/mcp/seriesEvidence.d.ts +10 -6
- package/dist/esm/mcp/seriesEvidence.js +16 -7
- package/dist/esm/mcp/seriesEvidence.js.map +1 -1
- package/dist/esm/mcp/terminate.d.ts +94 -0
- package/dist/esm/mcp/terminate.js +184 -0
- package/dist/esm/mcp/terminate.js.map +1 -0
- package/dist/esm/mcp/throttleRetry.js +71 -7
- package/dist/esm/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/mcp/toolList.d.ts +90 -0
- package/dist/esm/mcp/toolList.js +123 -0
- package/dist/esm/mcp/toolList.js.map +1 -0
- package/dist/esm/mcp/types.d.ts +197 -3
- package/dist/esm/redaction/knownStrings.js +34 -0
- package/dist/esm/redaction/knownStrings.js.map +1 -1
- package/dist/esm/tool-providers/index.d.ts +2 -2
- package/dist/esm/tool-providers/index.js +15 -1
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/esm/tools/mcpClientUse.d.ts +59 -0
- package/dist/esm/tools/mcpClientUse.js +216 -0
- package/dist/esm/tools/mcpClientUse.js.map +1 -0
- package/dist/esm/tools/toolProvider.d.ts +16 -0
- package/dist/esm/tools/toolSessions.d.ts +41 -0
- package/dist/esm/tools/toolSessions.js +41 -1
- package/dist/esm/tools/toolSessions.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/identity/types.js.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/boundedJson.js +14 -7
- package/dist/lib/boundedJson.js.map +1 -1
- package/dist/mcp/callChecks.js +247 -0
- package/dist/mcp/callChecks.js.map +1 -0
- package/dist/mcp/callLifetime.js +5 -2
- package/dist/mcp/callLifetime.js.map +1 -1
- package/dist/mcp/clientPort.js +38 -0
- package/dist/mcp/clientPort.js.map +1 -0
- package/dist/mcp/gatewayTransport.js +13 -3
- package/dist/mcp/gatewayTransport.js.map +1 -1
- package/dist/mcp/index.js +25 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/listingGenerations.js +80 -0
- package/dist/mcp/listingGenerations.js.map +1 -0
- package/dist/mcp/mcpClient.js +306 -59
- package/dist/mcp/mcpClient.js.map +1 -1
- package/dist/mcp/mockMcpClient.js +13 -0
- package/dist/mcp/mockMcpClient.js.map +1 -1
- package/dist/mcp/pool/boundTool.js +223 -0
- package/dist/mcp/pool/boundTool.js.map +1 -0
- package/dist/mcp/pool/clientSet.js +157 -0
- package/dist/mcp/pool/clientSet.js.map +1 -0
- package/dist/mcp/pool/definitions.js +174 -0
- package/dist/mcp/pool/definitions.js.map +1 -0
- package/dist/mcp/pool/errors.js +96 -0
- package/dist/mcp/pool/errors.js.map +1 -0
- package/dist/mcp/pool/identityKey.js +99 -0
- package/dist/mcp/pool/identityKey.js.map +1 -0
- package/dist/mcp/pool/lease.js +55 -0
- package/dist/mcp/pool/lease.js.map +1 -0
- package/dist/mcp/pool/listTools.js +150 -0
- package/dist/mcp/pool/listTools.js.map +1 -0
- package/dist/mcp/pool/mcpClientPool.js +155 -0
- package/dist/mcp/pool/mcpClientPool.js.map +1 -0
- package/dist/mcp/pool/options.js +123 -0
- package/dist/mcp/pool/options.js.map +1 -0
- package/dist/mcp/pool/plan.js +140 -0
- package/dist/mcp/pool/plan.js.map +1 -0
- package/dist/mcp/pool/pool.js +1075 -0
- package/dist/mcp/pool/pool.js.map +1 -0
- package/dist/mcp/pool/pooledClient.js +94 -0
- package/dist/mcp/pool/pooledClient.js.map +1 -0
- package/dist/mcp/pool/record.js +80 -0
- package/dist/mcp/pool/record.js.map +1 -0
- package/dist/mcp/pool/sessionEnded.js +35 -0
- package/dist/mcp/pool/sessionEnded.js.map +1 -0
- package/dist/mcp/pool/work.js +219 -0
- package/dist/mcp/pool/work.js.map +1 -0
- package/dist/mcp/requestGuard.js +106 -0
- package/dist/mcp/requestGuard.js.map +1 -0
- package/dist/mcp/requestLedger.js +76 -3
- package/dist/mcp/requestLedger.js.map +1 -1
- package/dist/mcp/seriesEvidence.js +16 -7
- package/dist/mcp/seriesEvidence.js.map +1 -1
- package/dist/mcp/terminate.js +193 -0
- package/dist/mcp/terminate.js.map +1 -0
- package/dist/mcp/throttleRetry.js +71 -7
- package/dist/mcp/throttleRetry.js.map +1 -1
- package/dist/mcp/toolList.js +128 -0
- package/dist/mcp/toolList.js.map +1 -0
- package/dist/redaction/knownStrings.js +34 -0
- package/dist/redaction/knownStrings.js.map +1 -1
- package/dist/tool-providers/index.js +20 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/tools/mcpClientUse.js +225 -0
- package/dist/tools/mcpClientUse.js.map +1 -0
- package/dist/tools/toolSessions.js +44 -1
- package/dist/tools/toolSessions.js.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
- package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/slots/buildToolsSlot.d.ts +12 -0
- package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +41 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/identity/types.d.ts +7 -3
- package/dist/types/identity/types.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/boundedJson.d.ts +14 -7
- package/dist/types/lib/boundedJson.d.ts.map +1 -1
- package/dist/types/mcp/callChecks.d.ts +161 -0
- package/dist/types/mcp/callChecks.d.ts.map +1 -0
- package/dist/types/mcp/callLifetime.d.ts.map +1 -1
- package/dist/types/mcp/clientPort.d.ts +79 -0
- package/dist/types/mcp/clientPort.d.ts.map +1 -0
- package/dist/types/mcp/gatewayTransport.d.ts.map +1 -1
- package/dist/types/mcp/index.d.ts +11 -1
- package/dist/types/mcp/index.d.ts.map +1 -1
- package/dist/types/mcp/listingGenerations.d.ts +55 -0
- package/dist/types/mcp/listingGenerations.d.ts.map +1 -0
- package/dist/types/mcp/mcpClient.d.ts +18 -1
- package/dist/types/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/mcp/mockMcpClient.d.ts.map +1 -1
- package/dist/types/mcp/pool/boundTool.d.ts +59 -0
- package/dist/types/mcp/pool/boundTool.d.ts.map +1 -0
- package/dist/types/mcp/pool/clientSet.d.ts +74 -0
- package/dist/types/mcp/pool/clientSet.d.ts.map +1 -0
- package/dist/types/mcp/pool/definitions.d.ts +104 -0
- package/dist/types/mcp/pool/definitions.d.ts.map +1 -0
- package/dist/types/mcp/pool/errors.d.ts +77 -0
- package/dist/types/mcp/pool/errors.d.ts.map +1 -0
- package/dist/types/mcp/pool/identityKey.d.ts +58 -0
- package/dist/types/mcp/pool/identityKey.d.ts.map +1 -0
- package/dist/types/mcp/pool/lease.d.ts +37 -0
- package/dist/types/mcp/pool/lease.d.ts.map +1 -0
- package/dist/types/mcp/pool/listTools.d.ts +34 -0
- package/dist/types/mcp/pool/listTools.d.ts.map +1 -0
- package/dist/types/mcp/pool/mcpClientPool.d.ts +122 -0
- package/dist/types/mcp/pool/mcpClientPool.d.ts.map +1 -0
- package/dist/types/mcp/pool/options.d.ts +184 -0
- package/dist/types/mcp/pool/options.d.ts.map +1 -0
- package/dist/types/mcp/pool/plan.d.ts +78 -0
- package/dist/types/mcp/pool/plan.d.ts.map +1 -0
- package/dist/types/mcp/pool/pool.d.ts +308 -0
- package/dist/types/mcp/pool/pool.d.ts.map +1 -0
- package/dist/types/mcp/pool/pooledClient.d.ts +94 -0
- package/dist/types/mcp/pool/pooledClient.d.ts.map +1 -0
- package/dist/types/mcp/pool/record.d.ts +81 -0
- package/dist/types/mcp/pool/record.d.ts.map +1 -0
- package/dist/types/mcp/pool/sessionEnded.d.ts +25 -0
- package/dist/types/mcp/pool/sessionEnded.d.ts.map +1 -0
- package/dist/types/mcp/pool/work.d.ts +117 -0
- package/dist/types/mcp/pool/work.d.ts.map +1 -0
- package/dist/types/mcp/requestGuard.d.ts +71 -0
- package/dist/types/mcp/requestGuard.d.ts.map +1 -0
- package/dist/types/mcp/requestLedger.d.ts +35 -1
- package/dist/types/mcp/requestLedger.d.ts.map +1 -1
- package/dist/types/mcp/seriesEvidence.d.ts +10 -6
- package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
- package/dist/types/mcp/terminate.d.ts +95 -0
- package/dist/types/mcp/terminate.d.ts.map +1 -0
- package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/mcp/toolList.d.ts +91 -0
- package/dist/types/mcp/toolList.d.ts.map +1 -0
- package/dist/types/mcp/types.d.ts +197 -3
- package/dist/types/mcp/types.d.ts.map +1 -1
- package/dist/types/redaction/knownStrings.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/dist/types/tools/mcpClientUse.d.ts +60 -0
- package/dist/types/tools/mcpClientUse.d.ts.map +1 -0
- package/dist/types/tools/toolProvider.d.ts +16 -0
- package/dist/types/tools/toolProvider.d.ts.map +1 -1
- package/dist/types/tools/toolSessions.d.ts +41 -0
- package/dist/types/tools/toolSessions.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* options — what `mcpClientPool` is built from, read and checked once.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: one options type + one reader that refuses by name.
|
|
5
|
+
* Role: The pool's budgets and clocks (`docs/design/2026-10-mcp-client-pool.md`
|
|
6
|
+
* § 3.1). Every number is checked when the pool is built, never at the
|
|
7
|
+
* first call. The pool takes the `mcpClient` options that shape one
|
|
8
|
+
* connection and hands them to every client it opens; it never takes
|
|
9
|
+
* `connection`, because it must build the transport itself — to end
|
|
10
|
+
* the session, to hear the tools-changed notice, and to place the send
|
|
11
|
+
* gate.
|
|
12
|
+
*/
|
|
13
|
+
import { replayDeclarationOf } from '../replay.js';
|
|
14
|
+
/** The defaults, named so a test and a docstring cannot drift from the code. */
|
|
15
|
+
export const MCP_POOL_DEFAULTS = Object.freeze({
|
|
16
|
+
maxClients: 64,
|
|
17
|
+
maxClientsPerPrincipal: 8,
|
|
18
|
+
maxEnding: 8,
|
|
19
|
+
maxOperations: 256,
|
|
20
|
+
initTimeoutMs: 30_000,
|
|
21
|
+
idleMs: 600_000,
|
|
22
|
+
maxLeaseMs: 900_000,
|
|
23
|
+
definitionTtlMs: 600_000,
|
|
24
|
+
});
|
|
25
|
+
/** At most this many shared definition entries are kept; the least recently used goes first. */
|
|
26
|
+
export const MAX_DEFINITION_ENTRIES = 256;
|
|
27
|
+
/** A list longer than this is used by its own client and never shared. */
|
|
28
|
+
export const MAX_SHARED_TOOLS = 512;
|
|
29
|
+
/**
|
|
30
|
+
* Read `options` once.
|
|
31
|
+
*
|
|
32
|
+
* @throws TypeError naming the option, when one is missing, mistyped or out of
|
|
33
|
+
* range, or when `connection` is given — here, when the pool is built.
|
|
34
|
+
*/
|
|
35
|
+
export function readPoolOptions(options) {
|
|
36
|
+
if (options === null || typeof options !== 'object') {
|
|
37
|
+
throw new TypeError('mcpClientPool: options must be an object with `name` and `transport`.');
|
|
38
|
+
}
|
|
39
|
+
const { name } = options;
|
|
40
|
+
if (typeof name !== 'string' || name.trim() === '') {
|
|
41
|
+
throw new TypeError('mcpClientPool: `name` must be a non-empty string — the server name every tool and record carries.');
|
|
42
|
+
}
|
|
43
|
+
const where = `mcpClientPool[${name}]`;
|
|
44
|
+
if (options.connection !== undefined) {
|
|
45
|
+
throw new TypeError(`${where}: \`connection\` is not taken. The pool builds every client's transport itself — ` +
|
|
46
|
+
'to end its session, to hear the tools-changed notice and to place the send gate. Pass ' +
|
|
47
|
+
'`transport`, or a function of the identity that returns one.');
|
|
48
|
+
}
|
|
49
|
+
const transport = transportOf(options.transport, where);
|
|
50
|
+
const count = (key) => positiveInteger(options[key], MCP_POOL_DEFAULTS[key], key, where);
|
|
51
|
+
const definitions = options.definitions ?? 'per-client';
|
|
52
|
+
if (definitions !== 'per-client' && typeof definitions?.share !== 'function') {
|
|
53
|
+
throw new TypeError(`${where}: \`definitions\` must be 'per-client' or { share: (identity) => names | undefined }.`);
|
|
54
|
+
}
|
|
55
|
+
if (options.onEvent !== undefined && typeof options.onEvent !== 'function') {
|
|
56
|
+
throw new TypeError(`${where}: \`onEvent\` must be a function.`);
|
|
57
|
+
}
|
|
58
|
+
if (options.now !== undefined && typeof options.now !== 'function') {
|
|
59
|
+
throw new TypeError(`${where}: the clock option must be a function returning milliseconds.`);
|
|
60
|
+
}
|
|
61
|
+
// Refused by field now, as each client would refuse it at its first open.
|
|
62
|
+
if (options.replay !== undefined)
|
|
63
|
+
replayDeclarationOf(options.replay, where);
|
|
64
|
+
return {
|
|
65
|
+
name,
|
|
66
|
+
transport,
|
|
67
|
+
maxClients: count('maxClients'),
|
|
68
|
+
maxClientsPerPrincipal: count('maxClientsPerPrincipal'),
|
|
69
|
+
maxEnding: count('maxEnding'),
|
|
70
|
+
maxOperations: count('maxOperations'),
|
|
71
|
+
initTimeoutMs: count('initTimeoutMs'),
|
|
72
|
+
idleMs: count('idleMs'),
|
|
73
|
+
maxLeaseMs: count('maxLeaseMs'),
|
|
74
|
+
definitionTtlMs: count('definitionTtlMs'),
|
|
75
|
+
share: definitions === 'per-client' ? undefined : definitions.share,
|
|
76
|
+
requirePrincipal: flag(options.requirePrincipal, true, 'requirePrincipal', where),
|
|
77
|
+
requireTenant: flag(options.requireTenant, false, 'requireTenant', where),
|
|
78
|
+
onEvent: options.onEvent,
|
|
79
|
+
client: {
|
|
80
|
+
...(options.resultMode !== undefined && { resultMode: options.resultMode }),
|
|
81
|
+
...(options.clientInfo !== undefined && { clientInfo: options.clientInfo }),
|
|
82
|
+
...(options.retryOnThrottle !== undefined && { retryOnThrottle: options.retryOnThrottle }),
|
|
83
|
+
...(options.replay !== undefined && { replay: options.replay }),
|
|
84
|
+
...(options.sdk !== undefined && { sdk: options.sdk }),
|
|
85
|
+
...(options.jsonSchemaValidator !== undefined && {
|
|
86
|
+
jsonSchemaValidator: options.jsonSchemaValidator,
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
now: options.now ?? Date.now,
|
|
90
|
+
open: options._open,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** One transport for everyone, or a function of the identity — as a function either way. */
|
|
94
|
+
function transportOf(value, where) {
|
|
95
|
+
if (typeof value === 'function')
|
|
96
|
+
return value;
|
|
97
|
+
if (value !== null && typeof value === 'object' && typeof value.transport === 'string') {
|
|
98
|
+
return () => value;
|
|
99
|
+
}
|
|
100
|
+
throw new TypeError(`${where}: \`transport\` must be an MCP transport ({ transport: 'http' | 'gateway' | 'stdio', … }) ` +
|
|
101
|
+
'or a function of the identity that returns one.');
|
|
102
|
+
}
|
|
103
|
+
/** A whole number ≥ 1, or the default when absent. */
|
|
104
|
+
function positiveInteger(value, fallback, key, where) {
|
|
105
|
+
if (value === undefined)
|
|
106
|
+
return fallback;
|
|
107
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= 1)
|
|
108
|
+
return value;
|
|
109
|
+
throw new TypeError(`${where}: \`${key}\` must be a whole number ≥ 1.`);
|
|
110
|
+
}
|
|
111
|
+
/** A boolean, or the default when absent. */
|
|
112
|
+
function flag(value, fallback, key, where) {
|
|
113
|
+
if (value === undefined)
|
|
114
|
+
return fallback;
|
|
115
|
+
if (typeof value === 'boolean')
|
|
116
|
+
return value;
|
|
117
|
+
throw new TypeError(`${where}: \`${key}\` must be true or false.`);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../../../src/mcp/pool/options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plan — what one client is opened from, resolved before anything opens, and
|
|
3
|
+
* the context its tool definitions belong to.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: a pure resolution step + two hashes.
|
|
6
|
+
* Role: § 6.1–6.2 of the design. A client is opened from a PLAN: the
|
|
7
|
+
* transport the factory returns for this identity, resolved at that
|
|
8
|
+
* moment and kept unchanged for the client's life. The plan's
|
|
9
|
+
* `configHash` is SHA-256 over a canonical encoding of the transport's
|
|
10
|
+
* comparable data — the pool name; the transport kind and URL; header
|
|
11
|
+
* names and a digest of their values; a gateway's service, scopes,
|
|
12
|
+
* mode and credential provider id; stdio's command, args and working
|
|
13
|
+
* directory; the transport's own stated `settings`; `resultMode` and
|
|
14
|
+
* `clientInfo`. A function (a `fetch`, an AWS client) cannot be
|
|
15
|
+
* compared: the app's `configuration` name covers it.
|
|
16
|
+
*
|
|
17
|
+
* The definitions CONTEXT is the binding a tool is listed under:
|
|
18
|
+
*
|
|
19
|
+
* - per client (the default): `pc:<configHash>` — the client's own list;
|
|
20
|
+
* - shared, when the app's `share` names both a configuration and an
|
|
21
|
+
* authorization: `sh:<sha256(configHash, configuration, authorization,
|
|
22
|
+
* tenant)>`. The tenant is always in it: the app's names widen sharing
|
|
23
|
+
* across principals, never across tenants.
|
|
24
|
+
*
|
|
25
|
+
* The transport is resolved once, when a client opens; the context is not. The
|
|
26
|
+
* app's names can move — a policy version in `authorization` — so the pool asks
|
|
27
|
+
* `share` again at every listing, every call and every send gate
|
|
28
|
+
* (`contextFor`), over the client's own `configHash`: a conversation that
|
|
29
|
+
* already has a client follows a new name as a new conversation would.
|
|
30
|
+
*
|
|
31
|
+
* Neither hash leaves the process; the app's names are hashed and never kept.
|
|
32
|
+
*/
|
|
33
|
+
import type { ClientPort, PooledClientSeam } from '../clientPort.js';
|
|
34
|
+
import type { McpClient, McpClientOptions, McpTransport } from '../types.js';
|
|
35
|
+
import type { PoolKey } from './identityKey.js';
|
|
36
|
+
import type { PoolSettings } from './options.js';
|
|
37
|
+
/** What a client is opened from. */
|
|
38
|
+
export interface ClientPlan {
|
|
39
|
+
readonly transport: McpTransport;
|
|
40
|
+
readonly configHash: string;
|
|
41
|
+
/** The definitions context: `pc:<configHash>` or `sh:<context>`. */
|
|
42
|
+
readonly context: string;
|
|
43
|
+
/** True when the app's sharing contract applies to this conversation. */
|
|
44
|
+
readonly shared: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** An opened client: the ordinary `McpClient`, and the port back (`clientPort.ts`). */
|
|
47
|
+
export interface OpenedClient {
|
|
48
|
+
readonly client: McpClient;
|
|
49
|
+
readonly port: ClientPort;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* How the pool opens one client. The real path is `openPooledClient`; a test
|
|
53
|
+
* injects its own (the `_open` seam).
|
|
54
|
+
*/
|
|
55
|
+
export type PoolClientOpener = (options: McpClientOptions, seam: PooledClientSeam) => Promise<OpenedClient>;
|
|
56
|
+
/**
|
|
57
|
+
* The plan for `key`: the transport the factory returns now, and the context
|
|
58
|
+
* its definitions belong to.
|
|
59
|
+
*
|
|
60
|
+
* @throws what the transport factory or `share` throws, and a TypeError when
|
|
61
|
+
* `share` answers with anything but two names or `undefined` — the caller
|
|
62
|
+
* refuses the open with `init-failed`, the error as its `cause`
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolvePlan(settings: PoolSettings, key: PoolKey): ClientPlan;
|
|
65
|
+
/**
|
|
66
|
+
* The definitions context `key` belongs to now, for a client opened with
|
|
67
|
+
* `configHash`: the app's `share` asked again.
|
|
68
|
+
*
|
|
69
|
+
* @throws what `share` throws, and a TypeError when it answers with anything
|
|
70
|
+
* but two names or `undefined`
|
|
71
|
+
*/
|
|
72
|
+
export declare function contextFor(settings: PoolSettings, key: PoolKey, configHash: string): {
|
|
73
|
+
readonly context: string;
|
|
74
|
+
readonly shared: boolean;
|
|
75
|
+
};
|
|
76
|
+
/** SHA-256 over the transport's comparable data (see the module note). */
|
|
77
|
+
export declare function configHashOf(settings: PoolSettings, transport: McpTransport): string;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plan — what one client is opened from, resolved before anything opens, and
|
|
3
|
+
* the context its tool definitions belong to.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: a pure resolution step + two hashes.
|
|
6
|
+
* Role: § 6.1–6.2 of the design. A client is opened from a PLAN: the
|
|
7
|
+
* transport the factory returns for this identity, resolved at that
|
|
8
|
+
* moment and kept unchanged for the client's life. The plan's
|
|
9
|
+
* `configHash` is SHA-256 over a canonical encoding of the transport's
|
|
10
|
+
* comparable data — the pool name; the transport kind and URL; header
|
|
11
|
+
* names and a digest of their values; a gateway's service, scopes,
|
|
12
|
+
* mode and credential provider id; stdio's command, args and working
|
|
13
|
+
* directory; the transport's own stated `settings`; `resultMode` and
|
|
14
|
+
* `clientInfo`. A function (a `fetch`, an AWS client) cannot be
|
|
15
|
+
* compared: the app's `configuration` name covers it.
|
|
16
|
+
*
|
|
17
|
+
* The definitions CONTEXT is the binding a tool is listed under:
|
|
18
|
+
*
|
|
19
|
+
* - per client (the default): `pc:<configHash>` — the client's own list;
|
|
20
|
+
* - shared, when the app's `share` names both a configuration and an
|
|
21
|
+
* authorization: `sh:<sha256(configHash, configuration, authorization,
|
|
22
|
+
* tenant)>`. The tenant is always in it: the app's names widen sharing
|
|
23
|
+
* across principals, never across tenants.
|
|
24
|
+
*
|
|
25
|
+
* The transport is resolved once, when a client opens; the context is not. The
|
|
26
|
+
* app's names can move — a policy version in `authorization` — so the pool asks
|
|
27
|
+
* `share` again at every listing, every call and every send gate
|
|
28
|
+
* (`contextFor`), over the client's own `configHash`: a conversation that
|
|
29
|
+
* already has a client follows a new name as a new conversation would.
|
|
30
|
+
*
|
|
31
|
+
* Neither hash leaves the process; the app's names are hashed and never kept.
|
|
32
|
+
*/
|
|
33
|
+
import { canonicalJson } from '../../lib/canonicalJson.js';
|
|
34
|
+
import { sha256Hex } from '../../lib/sha256.js';
|
|
35
|
+
/**
|
|
36
|
+
* The plan for `key`: the transport the factory returns now, and the context
|
|
37
|
+
* its definitions belong to.
|
|
38
|
+
*
|
|
39
|
+
* @throws what the transport factory or `share` throws, and a TypeError when
|
|
40
|
+
* `share` answers with anything but two names or `undefined` — the caller
|
|
41
|
+
* refuses the open with `init-failed`, the error as its `cause`
|
|
42
|
+
*/
|
|
43
|
+
export function resolvePlan(settings, key) {
|
|
44
|
+
const transport = settings.transport(key.identity);
|
|
45
|
+
if (transport === null ||
|
|
46
|
+
typeof transport !== 'object' ||
|
|
47
|
+
typeof transport.transport !== 'string') {
|
|
48
|
+
throw new TypeError(`mcpClientPool[${settings.name}]: the \`transport\` function returned something that is not an MCP transport.`);
|
|
49
|
+
}
|
|
50
|
+
const configHash = configHashOf(settings, transport);
|
|
51
|
+
return { transport, configHash, ...contextFor(settings, key, configHash) };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The definitions context `key` belongs to now, for a client opened with
|
|
55
|
+
* `configHash`: the app's `share` asked again.
|
|
56
|
+
*
|
|
57
|
+
* @throws what `share` throws, and a TypeError when it answers with anything
|
|
58
|
+
* but two names or `undefined`
|
|
59
|
+
*/
|
|
60
|
+
export function contextFor(settings, key, configHash) {
|
|
61
|
+
const names = shareOf(settings, key);
|
|
62
|
+
if (names === undefined)
|
|
63
|
+
return { context: `pc:${configHash}`, shared: false };
|
|
64
|
+
const context = sha256Hex(canonicalJson({
|
|
65
|
+
configHash,
|
|
66
|
+
configuration: names.configuration,
|
|
67
|
+
authorization: names.authorization,
|
|
68
|
+
tenant: key.tenant,
|
|
69
|
+
}));
|
|
70
|
+
return { context: `sh:${context}`, shared: true };
|
|
71
|
+
}
|
|
72
|
+
/** The app's two names for this conversation, or `undefined` for a list of its own. */
|
|
73
|
+
function shareOf(settings, key) {
|
|
74
|
+
if (settings.share === undefined)
|
|
75
|
+
return undefined;
|
|
76
|
+
const names = settings.share(key.identity);
|
|
77
|
+
if (names === undefined)
|
|
78
|
+
return undefined;
|
|
79
|
+
if (names !== null &&
|
|
80
|
+
typeof names === 'object' &&
|
|
81
|
+
typeof names.configuration === 'string' &&
|
|
82
|
+
typeof names.authorization === 'string') {
|
|
83
|
+
const { configuration, authorization } = names;
|
|
84
|
+
return { configuration, authorization };
|
|
85
|
+
}
|
|
86
|
+
throw new TypeError(`mcpClientPool[${settings.name}]: \`definitions.share\` must return { configuration, authorization } ` +
|
|
87
|
+
'(two strings) or undefined, synchronously.');
|
|
88
|
+
}
|
|
89
|
+
/** SHA-256 over the transport's comparable data (see the module note). */
|
|
90
|
+
export function configHashOf(settings, transport) {
|
|
91
|
+
return sha256Hex(canonicalJson({
|
|
92
|
+
pool: settings.name,
|
|
93
|
+
transport: comparableOf(transport),
|
|
94
|
+
resultMode: settings.client.resultMode ?? null,
|
|
95
|
+
clientInfo: settings.client.clientInfo ?? null,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
/** The comparable part of a transport: data only, functions left out. */
|
|
99
|
+
function comparableOf(transport) {
|
|
100
|
+
if (transport.transport === 'stdio') {
|
|
101
|
+
return {
|
|
102
|
+
kind: 'stdio',
|
|
103
|
+
command: transport.command,
|
|
104
|
+
args: [...(transport.args ?? [])],
|
|
105
|
+
cwd: transport.cwd ?? null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const headers = headersOf(transport.headers);
|
|
109
|
+
if (transport.transport === 'gateway') {
|
|
110
|
+
return {
|
|
111
|
+
kind: 'gateway',
|
|
112
|
+
url: transport.url,
|
|
113
|
+
headers,
|
|
114
|
+
service: transport.service,
|
|
115
|
+
scopes: [...(transport.scopes ?? [])],
|
|
116
|
+
mode: transport.mode ?? null,
|
|
117
|
+
credentials: transport.credentials?.id ?? null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
kind: 'http',
|
|
122
|
+
url: transport.url,
|
|
123
|
+
headers,
|
|
124
|
+
settings: transport.settings ?? null,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** Header names, and a digest of their values — never the values themselves. */
|
|
128
|
+
function headersOf(headers) {
|
|
129
|
+
if (headers === undefined)
|
|
130
|
+
return { names: [], digest: null };
|
|
131
|
+
const lowered = Object.fromEntries(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), value]));
|
|
132
|
+
return { names: Object.keys(lowered).sort(), digest: sha256Hex(canonicalJson(lowered)) };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/mcp/pool/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pool — the state behind `mcpClientPool`: who holds which client, what is
|
|
3
|
+
* charged, and what ends when.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: one state machine, mutated only between awaits.
|
|
6
|
+
* Role: §§ 5–7 of the design. Every mutation of the sets and the budget runs
|
|
7
|
+
* synchronously — a check and the move it allows are never split by
|
|
8
|
+
* an await — so two callers cannot both take the last slot.
|
|
9
|
+
*
|
|
10
|
+
* - ADMISSION: every listing, call, acquire and ending is admitted against
|
|
11
|
+
* `maxOperations` before anything is sent. At each interaction the lazy
|
|
12
|
+
* sweep (revoked leases, idle ends, deferred ends) runs FIRST, so it
|
|
13
|
+
* reserves its endings before the new operation is admitted.
|
|
14
|
+
* - ONE OPEN PER KEY, from a plan resolved at that moment, under the pool's own
|
|
15
|
+
* signal and `initTimeoutMs`, never a caller's. A caller that gives up
|
|
16
|
+
* detaches alone; the operation that started the open keeps its charge until
|
|
17
|
+
* the open's work settles. Past the deadline every waiter is refused at once
|
|
18
|
+
* (`init-timeout`), and until the open's work settles the key cannot open
|
|
19
|
+
* again. A failure reaches every current waiter and is not cached.
|
|
20
|
+
* - THE HANDOFF: every operation waiting for an open holds a RESERVATION on
|
|
21
|
+
* the client until it takes its lease, so between the open settling and
|
|
22
|
+
* that lease the client is busy — nobody can evict, idle-end or end it. The
|
|
23
|
+
* client's state is checked again after every wait, and the lease taken in
|
|
24
|
+
* the same step: a lease is never handed out on a client that is ending.
|
|
25
|
+
* - MAKING ROOM: the principal's, then the pool's, least recently used IDLE
|
|
26
|
+
* client moves to the ending set — or `PoolFullError` at once.
|
|
27
|
+
* - ENDING reserves an ending slot and an operation slot FIRST; when either is
|
|
28
|
+
* full the client stays in the open set, counted, reported deferred, and is
|
|
29
|
+
* ended when slots free. Every end goes through `terminate()` — but a client
|
|
30
|
+
* whose handle this process lost: nothing can be sent for it, so its ending
|
|
31
|
+
* is its local close alone, charged the same way until it settles.
|
|
32
|
+
* - SETTLEMENT, never an abort, returns a slot (`work.ts`).
|
|
33
|
+
* - NOTHING UNCHECKED: on a pooled client every request carries a guard — its
|
|
34
|
+
* call's, or the client's open, listing or ending — and a request with none
|
|
35
|
+
* is refused before it is sent (`request-unmatched`), at the watched `send`
|
|
36
|
+
* and at the pool's own fetch alike.
|
|
37
|
+
*/
|
|
38
|
+
import type { Tool } from '../../tools/tools.js';
|
|
39
|
+
import type { McpTerminateOutcome } from '../types.js';
|
|
40
|
+
import { ClientSet, type PreviousEnd } from './clientSet.js';
|
|
41
|
+
import { SharedDefinitions, type Definition, type DefinitionList } from './definitions.js';
|
|
42
|
+
import { McpPoolRefusedError, PoolFullError, type McpPoolLimit } from './errors.js';
|
|
43
|
+
import { type PoolKey } from './identityKey.js';
|
|
44
|
+
import { type PoolSettings } from './options.js';
|
|
45
|
+
import { type ClientPlan } from './plan.js';
|
|
46
|
+
import { PooledClient, type EndReason } from './pooledClient.js';
|
|
47
|
+
import { Reporter, type UseFacts } from './record.js';
|
|
48
|
+
import { OperationBudget, Work, type Operation, type OperationKind, type WorkKind } from './work.js';
|
|
49
|
+
/** An app lease, as the pool tracks it for `maxLeaseMs`. */
|
|
50
|
+
export interface HeldLease {
|
|
51
|
+
readonly client: PooledClient;
|
|
52
|
+
readonly takenAt: number;
|
|
53
|
+
/** Revoked: its next use throws `lease-expired`. */
|
|
54
|
+
revoked: boolean;
|
|
55
|
+
/** Released: idempotent. */
|
|
56
|
+
released: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** Where a list's definitions live: a client's own, or a shared entry. */
|
|
59
|
+
export interface ServedList {
|
|
60
|
+
readonly list: DefinitionList;
|
|
61
|
+
readonly shared: boolean;
|
|
62
|
+
/** The definitions context: `pc:` or `sh:`. */
|
|
63
|
+
readonly context: string;
|
|
64
|
+
}
|
|
65
|
+
/** What `stats()` returns: counts, never keys. */
|
|
66
|
+
export interface McpPoolStats {
|
|
67
|
+
/** Clients in the open set: opening, busy or idle. */
|
|
68
|
+
readonly open: number;
|
|
69
|
+
readonly busy: number;
|
|
70
|
+
readonly idle: number;
|
|
71
|
+
readonly opening: number;
|
|
72
|
+
/** Clients being ended, until each ending's work has settled. */
|
|
73
|
+
readonly ending: number;
|
|
74
|
+
/** Operations charged. */
|
|
75
|
+
readonly operations: number;
|
|
76
|
+
/** Shared definition entries kept. */
|
|
77
|
+
readonly entries: number;
|
|
78
|
+
/** Charged work past its deadline that has not settled, by what it is doing. */
|
|
79
|
+
readonly unsettled: Readonly<Record<WorkKind, number>>;
|
|
80
|
+
/** Endings whose remote outcome was not confirmed. */
|
|
81
|
+
readonly unresolvedEndings: number;
|
|
82
|
+
}
|
|
83
|
+
export declare class Pool {
|
|
84
|
+
readonly settings: PoolSettings;
|
|
85
|
+
readonly clients: ClientSet;
|
|
86
|
+
readonly budget: OperationBudget;
|
|
87
|
+
readonly shared: SharedDefinitions;
|
|
88
|
+
readonly reporter: Reporter;
|
|
89
|
+
/** The pool's own signal: what every open, listing and call runs under; aborted at `close()`. */
|
|
90
|
+
private readonly lifetime;
|
|
91
|
+
private readonly leases;
|
|
92
|
+
private readonly settleWaiters;
|
|
93
|
+
/** Waiting for some client to become idle (`terminate`, `close`). */
|
|
94
|
+
private readonly idleWaiters;
|
|
95
|
+
closed: boolean;
|
|
96
|
+
unresolvedEndings: number;
|
|
97
|
+
constructor(settings: PoolSettings);
|
|
98
|
+
now(): number;
|
|
99
|
+
get signal(): AbortSignal;
|
|
100
|
+
/**
|
|
101
|
+
* The lazy sweep, run at the start of every interaction: leases past
|
|
102
|
+
* `maxLeaseMs` revoked, idle clients ended, deferred endings retried — all of
|
|
103
|
+
* it before a new operation is admitted.
|
|
104
|
+
*/
|
|
105
|
+
interact(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Admit one operation, or refuse at once: `closed`, or `PoolFullError`
|
|
108
|
+
* (`limit: 'operations'`) — before anything is sent.
|
|
109
|
+
*/
|
|
110
|
+
admit(kind: OperationKind, phase: WorkKind, callerSignal: AbortSignal | undefined): Operation;
|
|
111
|
+
refused(reason: McpPoolRefusedError['reason'], cause?: unknown): McpPoolRefusedError;
|
|
112
|
+
full(limit: McpPoolLimit): PoolFullError;
|
|
113
|
+
/**
|
|
114
|
+
* A library lease on `key`'s client for `operation`, opening one when the key
|
|
115
|
+
* has none (inside the operation's slot). `plan` is the plan resolved for a
|
|
116
|
+
* new client; a key that already has one keeps its own. The lease is
|
|
117
|
+
* released when the operation SETTLES.
|
|
118
|
+
*/
|
|
119
|
+
leaseClient(key: PoolKey, operation: Operation, facts: UseFacts, plan?: ClientPlan): Promise<PooledClient>;
|
|
120
|
+
/**
|
|
121
|
+
* Wait for `client`'s open inside `operation`, holding a reservation on it
|
|
122
|
+
* all the while — between the open settling and this lease the client is
|
|
123
|
+
* busy, so nobody can evict, idle-end or end it — then check it again and
|
|
124
|
+
* lease it in the same step, with no wait between. `undefined` when it no
|
|
125
|
+
* longer serves: the caller's next round finds the key's next client.
|
|
126
|
+
*/
|
|
127
|
+
private leaseOnceOpen;
|
|
128
|
+
/** `client` may have just become idle: a deferred ending may run, and a waiter for idleness may go on. */
|
|
129
|
+
private becameIdle;
|
|
130
|
+
private takeLease;
|
|
131
|
+
/** One lease ended: the client may now be idle, and a deferred ending may run. */
|
|
132
|
+
releaseLease(client: PooledClient): void;
|
|
133
|
+
private notifyIdle;
|
|
134
|
+
/** An app lease: a hold on a client for as long as the app keeps it, at most `maxLeaseMs`. */
|
|
135
|
+
holdLease(client: PooledClient): HeldLease;
|
|
136
|
+
/** End an app lease — at most once, whether released or revoked. */
|
|
137
|
+
endLease(lease: HeldLease): void;
|
|
138
|
+
private revokeExpiredLeases;
|
|
139
|
+
/** Every app lease is revoked: the pool is closing. */
|
|
140
|
+
revokeAllLeases(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Open a client for `key`: make room, resolve its plan, admit it to the open
|
|
143
|
+
* set, and start the one open. The operation that started it tracks the open's
|
|
144
|
+
* settlement, so its charge stays until the open's work has settled.
|
|
145
|
+
*/
|
|
146
|
+
private openFor;
|
|
147
|
+
/** The one open of `client`, under the pool's own signal and `initTimeoutMs`. */
|
|
148
|
+
private startOpen;
|
|
149
|
+
private dropFailedOpen;
|
|
150
|
+
/** Wait for `client`'s open inside `operation`: the caller's signal detaches the caller only. */
|
|
151
|
+
private waitOpen;
|
|
152
|
+
/** What `mcpClient` is opened with: the connection-shaping options, the pool's signal. */
|
|
153
|
+
private clientOptions;
|
|
154
|
+
/** What only a pool asks of the client it opens (`clientPort.ts`). */
|
|
155
|
+
private seamFor;
|
|
156
|
+
/**
|
|
157
|
+
* The guard for a message on `client` that carries none of its own: a tool
|
|
158
|
+
* call always brings its call's guard, so one without it is refused; any
|
|
159
|
+
* other request runs under the client's open, listing or ending — and with
|
|
160
|
+
* none under way, it is refused too. Nothing pooled is sent unchecked.
|
|
161
|
+
*/
|
|
162
|
+
private guardOf;
|
|
163
|
+
/** The guard of a request nothing covers: it refuses, so the request is never sent. */
|
|
164
|
+
private readonly unmatched;
|
|
165
|
+
/**
|
|
166
|
+
* The pool's own fetch, outermost on every pooled transport: a request is
|
|
167
|
+
* checked against its guard (the pooled call's, else the client's phase) and
|
|
168
|
+
* counted under it; the guard's signal is linked in; and the answer is read
|
|
169
|
+
* for the two pieces of evidence the pool classifies on — a 404 the MCP server
|
|
170
|
+
* itself sent to a request that carried its session id, and a handle this
|
|
171
|
+
* process lost. The client's own standalone stream (a GET), a notification and
|
|
172
|
+
* an answer to the server's own request are the client's, not an operation's:
|
|
173
|
+
* they pass untouched. Any other request with no guard is refused unsent.
|
|
174
|
+
*/
|
|
175
|
+
private pooledFetch;
|
|
176
|
+
/**
|
|
177
|
+
* Make room for a new client of `key`: the principal's least recently used
|
|
178
|
+
* idle client, then the pool's, moves to the ending set — or `PoolFullError`
|
|
179
|
+
* at once, naming the budget. There is no queue.
|
|
180
|
+
*/
|
|
181
|
+
private makeRoom;
|
|
182
|
+
/**
|
|
183
|
+
* Move `victim` to the ending set to make room. When the slots cannot be
|
|
184
|
+
* reserved, the arrival is refused at once, and the victim stays in the open
|
|
185
|
+
* set, counted, reported deferred — ended once slots free.
|
|
186
|
+
*/
|
|
187
|
+
private evict;
|
|
188
|
+
/** An ending slot and an operation slot, both, or which one is full. */
|
|
189
|
+
private reserveEnding;
|
|
190
|
+
/**
|
|
191
|
+
* End `client` for `reason` — when it is idle and both slots can be reserved.
|
|
192
|
+
* Otherwise it stays in the open set, still counted, and is reported deferred
|
|
193
|
+
* (once); it is ended when its last lease ends or slots free.
|
|
194
|
+
*/
|
|
195
|
+
endClient(client: PooledClient, reason: EndReason): void;
|
|
196
|
+
private defer;
|
|
197
|
+
/**
|
|
198
|
+
* Move `client` into the ending set under `operation`, and end it through
|
|
199
|
+
* `terminate()` — or, for a lost handle, through its local close alone.
|
|
200
|
+
*/
|
|
201
|
+
private startEnding;
|
|
202
|
+
private noteEnded;
|
|
203
|
+
/**
|
|
204
|
+
* A client whose handle this process lost: nothing can be sent for it, so it
|
|
205
|
+
* leaves its key at once — the next use opens the key's next client — and is
|
|
206
|
+
* ended under the ending rule like any other: its ending is its LOCAL close,
|
|
207
|
+
* charged an ending slot and an operation slot until that close settles, its
|
|
208
|
+
* remote outcome recorded unresolved. Busy, or with no slots free, it waits —
|
|
209
|
+
* still counted in the open set, reported deferred.
|
|
210
|
+
*/
|
|
211
|
+
lostHandle(client: PooledClient): void;
|
|
212
|
+
/** A client whose session the server ended: no new lease; ended (through `terminate()`) when idle. */
|
|
213
|
+
expired(client: PooledClient): void;
|
|
214
|
+
private sweepIdle;
|
|
215
|
+
/** Retry every deferred ending whose client is now idle. */
|
|
216
|
+
retryDeferred(): void;
|
|
217
|
+
/** Where `client`'s definitions are served from: its shared entry, or its own list. */
|
|
218
|
+
servedListOf(client: PooledClient): ServedList;
|
|
219
|
+
/**
|
|
220
|
+
* The definitions context `client` serves under NOW: the app's `share` asked
|
|
221
|
+
* again over the client's own configuration. A changed answer moves the
|
|
222
|
+
* client to the new context and stops serving its own list, so every tool
|
|
223
|
+
* bound under the old one is refused before it is sent.
|
|
224
|
+
*
|
|
225
|
+
* @throws `binding-changed`, `share`'s error as its cause, when the answer
|
|
226
|
+
* cannot be had — never the old context
|
|
227
|
+
*/
|
|
228
|
+
refreshContext(client: PooledClient): PooledClient['definitions'];
|
|
229
|
+
/** Does `context` still name the definitions context `client` serves under? False when it cannot be had. */
|
|
230
|
+
contextHolds(client: PooledClient, context: string): boolean;
|
|
231
|
+
/**
|
|
232
|
+
* The list `client` serves under NOW, listed again on it when it cannot be
|
|
233
|
+
* served as it stands — one listing at a time per list; a second caller joins
|
|
234
|
+
* it inside its own slot. Every attempt asks the app's names again
|
|
235
|
+
* (`refreshContext`), so a listing that a moved context discarded or refused
|
|
236
|
+
* at its send is listed once more under the context of now, never written
|
|
237
|
+
* into the one it began under. A listing raced by an invalidation is
|
|
238
|
+
* discarded too. Refused (`stale-tools`) when three attempts serve nothing.
|
|
239
|
+
* What it returns was checked against the context with no wait since.
|
|
240
|
+
*/
|
|
241
|
+
ensureListed(client: PooledClient, operation: Operation): Promise<ServedList>;
|
|
242
|
+
/**
|
|
243
|
+
* What `client` can serve under the context of now — asked of the app's names
|
|
244
|
+
* here — or, when nothing can, the list it should list. Too long to share:
|
|
245
|
+
* the conversation's own client keeps that list, under the same context.
|
|
246
|
+
*/
|
|
247
|
+
private servableNow;
|
|
248
|
+
/**
|
|
249
|
+
* One listing on `client` for `served`'s context. Its requests are sent only
|
|
250
|
+
* while that context holds — asked at every boundary they cross — and its
|
|
251
|
+
* answer is written only if the context still holds when it arrives and the
|
|
252
|
+
* list's generation held: an answer the app's names moved under belongs to
|
|
253
|
+
* no context, and is dropped.
|
|
254
|
+
*/
|
|
255
|
+
private startListing;
|
|
256
|
+
/**
|
|
257
|
+
* A request failed: when the pool's fetch read the server's own 404 for the
|
|
258
|
+
* session, or this process lost the handle, the client leaves its key — the
|
|
259
|
+
* next use opens the next client under the SAME key — and the error says so.
|
|
260
|
+
*/
|
|
261
|
+
classifyFailure(client: PooledClient, work: Work, error: unknown): RequestEvidenceOutcome;
|
|
262
|
+
/** The server said a client's tool list changed: that client's list and its shared entry. */
|
|
263
|
+
private toolsChangedOn;
|
|
264
|
+
/** The app's permission signal: every list in the scope. */
|
|
265
|
+
permissionsChanged(scope: {
|
|
266
|
+
readonly tenant?: string;
|
|
267
|
+
readonly principal?: string;
|
|
268
|
+
}): void;
|
|
269
|
+
/** The server changed: every list. */
|
|
270
|
+
toolsChanged(): void;
|
|
271
|
+
/**
|
|
272
|
+
* Stop new leases on every client `scope` names, at once; wait for their
|
|
273
|
+
* in-flight work up to `waitMs`; then end each one whose slots can be
|
|
274
|
+
* reserved. The rest are reported deferred and ended when they can be.
|
|
275
|
+
*/
|
|
276
|
+
terminate(matches: (key: PoolKey) => boolean, reason: EndReason, waitMs: number): Promise<readonly McpTerminateOutcome[]>;
|
|
277
|
+
/** End each of `clients` whose slots can be reserved; the outcomes of those that started. */
|
|
278
|
+
private endNow;
|
|
279
|
+
/** Wait until every client in `clients` is idle, or `waitMs` passed. */
|
|
280
|
+
private waitIdle;
|
|
281
|
+
/**
|
|
282
|
+
* Close: refuse new work, revoke app leases, abort in-flight work through the
|
|
283
|
+
* pool's own signal, then end every client as slots can be reserved — at most
|
|
284
|
+
* `maxEnding` at a time — in rounds, each bounded by `waitMs` (and each
|
|
285
|
+
* ending's answer by its own deadline). What could not be ended yet is
|
|
286
|
+
* reported deferred and ended when slots free; work still unsettled stays
|
|
287
|
+
* charged until it settles.
|
|
288
|
+
*/
|
|
289
|
+
closeAll(waitMs: number): Promise<readonly McpTerminateOutcome[]>;
|
|
290
|
+
/** Wait until an ending slot and an operation slot are free, or `waitMs` passed. */
|
|
291
|
+
private waitSlots;
|
|
292
|
+
/** Refuse new work, revoke app leases, abort in-flight work through the pool's signal. */
|
|
293
|
+
shutDown(): void;
|
|
294
|
+
/** Resolve once every charged operation and every ending has settled. */
|
|
295
|
+
settled(): Promise<void>;
|
|
296
|
+
private quiet;
|
|
297
|
+
private notifySettled;
|
|
298
|
+
stats(): McpPoolStats;
|
|
299
|
+
/** The bound shape of every definition in `served`, for a client of `key`. */
|
|
300
|
+
definitionsOf(served: ServedList): readonly Definition[];
|
|
301
|
+
/** The tools a list's client-own entries carry, by name (per-client lists only). */
|
|
302
|
+
ownTool(served: ServedList, name: string): Tool | undefined;
|
|
303
|
+
}
|
|
304
|
+
/** What a failed request proved about its client, if anything. */
|
|
305
|
+
export type RequestEvidenceOutcome = 'expired' | 'handle-lost' | undefined;
|
|
306
|
+
/** Re-exported for the bound tool: which end reasons name a previous client. */
|
|
307
|
+
export type { PreviousEnd };
|