agentfootprint 12.1.0 → 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.
Files changed (275) hide show
  1. package/AGENTS.md +1 -1
  2. package/CAPABILITIES.md +3 -1
  3. package/ai-instructions/claude-code/SKILL.md +1 -1
  4. package/dist/adapters/mcp/agentcoreRuntime/invoke.js +113 -7
  5. package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  6. package/dist/adapters/mcp/agentcoreRuntime/session.js +21 -21
  7. package/dist/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
  8. package/dist/adapters/mcp/agentcoreRuntime/transport.js +79 -5
  9. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  10. package/dist/core/Agent.js +6 -0
  11. package/dist/core/Agent.js.map +1 -1
  12. package/dist/core/agent/stages/toolCalls.js +4 -0
  13. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  14. package/dist/core/slots/buildToolsSlot.js +8 -0
  15. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  16. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
  17. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +112 -6
  18. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  19. package/dist/esm/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
  20. package/dist/esm/adapters/mcp/agentcoreRuntime/session.js +21 -21
  21. package/dist/esm/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
  22. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +81 -7
  23. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  24. package/dist/esm/core/Agent.js +6 -0
  25. package/dist/esm/core/Agent.js.map +1 -1
  26. package/dist/esm/core/agent/stages/toolCalls.js +4 -0
  27. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  28. package/dist/esm/core/slots/buildToolsSlot.d.ts +12 -0
  29. package/dist/esm/core/slots/buildToolsSlot.js +8 -0
  30. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  31. package/dist/esm/events/payloads.d.ts +41 -0
  32. package/dist/esm/events/registry.d.ts +3 -1
  33. package/dist/esm/events/registry.js +2 -0
  34. package/dist/esm/events/registry.js.map +1 -1
  35. package/dist/esm/identity/types.d.ts +7 -3
  36. package/dist/esm/identity/types.js.map +1 -1
  37. package/dist/esm/index.d.ts +1 -1
  38. package/dist/esm/index.js +4 -1
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/lib/boundedJson.d.ts +14 -7
  41. package/dist/esm/lib/boundedJson.js +14 -7
  42. package/dist/esm/lib/boundedJson.js.map +1 -1
  43. package/dist/esm/mcp/callLifetime.js +5 -2
  44. package/dist/esm/mcp/callLifetime.js.map +1 -1
  45. package/dist/esm/mcp/clientPort.d.ts +78 -0
  46. package/dist/esm/mcp/clientPort.js +33 -0
  47. package/dist/esm/mcp/clientPort.js.map +1 -0
  48. package/dist/esm/mcp/gatewayTransport.js +13 -3
  49. package/dist/esm/mcp/gatewayTransport.js.map +1 -1
  50. package/dist/esm/mcp/index.d.ts +9 -1
  51. package/dist/esm/mcp/index.js +8 -0
  52. package/dist/esm/mcp/index.js.map +1 -1
  53. package/dist/esm/mcp/mcpClient.d.ts +18 -1
  54. package/dist/esm/mcp/mcpClient.js +203 -43
  55. package/dist/esm/mcp/mcpClient.js.map +1 -1
  56. package/dist/esm/mcp/mockMcpClient.js +13 -0
  57. package/dist/esm/mcp/mockMcpClient.js.map +1 -1
  58. package/dist/esm/mcp/pool/boundTool.d.ts +58 -0
  59. package/dist/esm/mcp/pool/boundTool.js +218 -0
  60. package/dist/esm/mcp/pool/boundTool.js.map +1 -0
  61. package/dist/esm/mcp/pool/clientSet.d.ts +73 -0
  62. package/dist/esm/mcp/pool/clientSet.js +152 -0
  63. package/dist/esm/mcp/pool/clientSet.js.map +1 -0
  64. package/dist/esm/mcp/pool/definitions.d.ts +103 -0
  65. package/dist/esm/mcp/pool/definitions.js +168 -0
  66. package/dist/esm/mcp/pool/definitions.js.map +1 -0
  67. package/dist/esm/mcp/pool/errors.d.ts +76 -0
  68. package/dist/esm/mcp/pool/errors.js +91 -0
  69. package/dist/esm/mcp/pool/errors.js.map +1 -0
  70. package/dist/esm/mcp/pool/identityKey.d.ts +57 -0
  71. package/dist/esm/mcp/pool/identityKey.js +94 -0
  72. package/dist/esm/mcp/pool/identityKey.js.map +1 -0
  73. package/dist/esm/mcp/pool/lease.d.ts +36 -0
  74. package/dist/esm/mcp/pool/lease.js +51 -0
  75. package/dist/esm/mcp/pool/lease.js.map +1 -0
  76. package/dist/esm/mcp/pool/listTools.d.ts +33 -0
  77. package/dist/esm/mcp/pool/listTools.js +146 -0
  78. package/dist/esm/mcp/pool/listTools.js.map +1 -0
  79. package/dist/esm/mcp/pool/mcpClientPool.d.ts +121 -0
  80. package/dist/esm/mcp/pool/mcpClientPool.js +151 -0
  81. package/dist/esm/mcp/pool/mcpClientPool.js.map +1 -0
  82. package/dist/esm/mcp/pool/options.d.ts +183 -0
  83. package/dist/esm/mcp/pool/options.js +119 -0
  84. package/dist/esm/mcp/pool/options.js.map +1 -0
  85. package/dist/esm/mcp/pool/plan.d.ts +77 -0
  86. package/dist/esm/mcp/pool/plan.js +134 -0
  87. package/dist/esm/mcp/pool/plan.js.map +1 -0
  88. package/dist/esm/mcp/pool/pool.d.ts +307 -0
  89. package/dist/esm/mcp/pool/pool.js +1071 -0
  90. package/dist/esm/mcp/pool/pool.js.map +1 -0
  91. package/dist/esm/mcp/pool/pooledClient.d.ts +93 -0
  92. package/dist/esm/mcp/pool/pooledClient.js +90 -0
  93. package/dist/esm/mcp/pool/pooledClient.js.map +1 -0
  94. package/dist/esm/mcp/pool/record.d.ts +80 -0
  95. package/dist/esm/mcp/pool/record.js +75 -0
  96. package/dist/esm/mcp/pool/record.js.map +1 -0
  97. package/dist/esm/mcp/pool/sessionEnded.d.ts +24 -0
  98. package/dist/esm/mcp/pool/sessionEnded.js +31 -0
  99. package/dist/esm/mcp/pool/sessionEnded.js.map +1 -0
  100. package/dist/esm/mcp/pool/work.d.ts +116 -0
  101. package/dist/esm/mcp/pool/work.js +213 -0
  102. package/dist/esm/mcp/pool/work.js.map +1 -0
  103. package/dist/esm/mcp/requestGuard.d.ts +70 -0
  104. package/dist/esm/mcp/requestGuard.js +98 -0
  105. package/dist/esm/mcp/requestGuard.js.map +1 -0
  106. package/dist/esm/mcp/requestLedger.d.ts +35 -1
  107. package/dist/esm/mcp/requestLedger.js +76 -3
  108. package/dist/esm/mcp/requestLedger.js.map +1 -1
  109. package/dist/esm/mcp/seriesEvidence.d.ts +10 -6
  110. package/dist/esm/mcp/seriesEvidence.js +16 -7
  111. package/dist/esm/mcp/seriesEvidence.js.map +1 -1
  112. package/dist/esm/mcp/terminate.d.ts +94 -0
  113. package/dist/esm/mcp/terminate.js +184 -0
  114. package/dist/esm/mcp/terminate.js.map +1 -0
  115. package/dist/esm/mcp/throttleRetry.js +71 -7
  116. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  117. package/dist/esm/mcp/types.d.ts +85 -7
  118. package/dist/esm/redaction/knownStrings.js +34 -0
  119. package/dist/esm/redaction/knownStrings.js.map +1 -1
  120. package/dist/esm/tool-providers/index.d.ts +2 -2
  121. package/dist/esm/tool-providers/index.js +7 -1
  122. package/dist/esm/tool-providers/index.js.map +1 -1
  123. package/dist/esm/tools/mcpClientUse.d.ts +59 -0
  124. package/dist/esm/tools/mcpClientUse.js +216 -0
  125. package/dist/esm/tools/mcpClientUse.js.map +1 -0
  126. package/dist/esm/tools/toolProvider.d.ts +16 -0
  127. package/dist/esm/tools/toolSessions.d.ts +41 -0
  128. package/dist/esm/tools/toolSessions.js +41 -1
  129. package/dist/esm/tools/toolSessions.js.map +1 -1
  130. package/dist/events/registry.js +2 -0
  131. package/dist/events/registry.js.map +1 -1
  132. package/dist/identity/types.js.map +1 -1
  133. package/dist/index.js +6 -3
  134. package/dist/index.js.map +1 -1
  135. package/dist/lib/boundedJson.js +14 -7
  136. package/dist/lib/boundedJson.js.map +1 -1
  137. package/dist/mcp/callLifetime.js +5 -2
  138. package/dist/mcp/callLifetime.js.map +1 -1
  139. package/dist/mcp/clientPort.js +38 -0
  140. package/dist/mcp/clientPort.js.map +1 -0
  141. package/dist/mcp/gatewayTransport.js +13 -3
  142. package/dist/mcp/gatewayTransport.js.map +1 -1
  143. package/dist/mcp/index.js +16 -1
  144. package/dist/mcp/index.js.map +1 -1
  145. package/dist/mcp/mcpClient.js +207 -45
  146. package/dist/mcp/mcpClient.js.map +1 -1
  147. package/dist/mcp/mockMcpClient.js +13 -0
  148. package/dist/mcp/mockMcpClient.js.map +1 -1
  149. package/dist/mcp/pool/boundTool.js +223 -0
  150. package/dist/mcp/pool/boundTool.js.map +1 -0
  151. package/dist/mcp/pool/clientSet.js +157 -0
  152. package/dist/mcp/pool/clientSet.js.map +1 -0
  153. package/dist/mcp/pool/definitions.js +174 -0
  154. package/dist/mcp/pool/definitions.js.map +1 -0
  155. package/dist/mcp/pool/errors.js +96 -0
  156. package/dist/mcp/pool/errors.js.map +1 -0
  157. package/dist/mcp/pool/identityKey.js +99 -0
  158. package/dist/mcp/pool/identityKey.js.map +1 -0
  159. package/dist/mcp/pool/lease.js +55 -0
  160. package/dist/mcp/pool/lease.js.map +1 -0
  161. package/dist/mcp/pool/listTools.js +150 -0
  162. package/dist/mcp/pool/listTools.js.map +1 -0
  163. package/dist/mcp/pool/mcpClientPool.js +155 -0
  164. package/dist/mcp/pool/mcpClientPool.js.map +1 -0
  165. package/dist/mcp/pool/options.js +123 -0
  166. package/dist/mcp/pool/options.js.map +1 -0
  167. package/dist/mcp/pool/plan.js +140 -0
  168. package/dist/mcp/pool/plan.js.map +1 -0
  169. package/dist/mcp/pool/pool.js +1075 -0
  170. package/dist/mcp/pool/pool.js.map +1 -0
  171. package/dist/mcp/pool/pooledClient.js +94 -0
  172. package/dist/mcp/pool/pooledClient.js.map +1 -0
  173. package/dist/mcp/pool/record.js +80 -0
  174. package/dist/mcp/pool/record.js.map +1 -0
  175. package/dist/mcp/pool/sessionEnded.js +35 -0
  176. package/dist/mcp/pool/sessionEnded.js.map +1 -0
  177. package/dist/mcp/pool/work.js +219 -0
  178. package/dist/mcp/pool/work.js.map +1 -0
  179. package/dist/mcp/requestGuard.js +106 -0
  180. package/dist/mcp/requestGuard.js.map +1 -0
  181. package/dist/mcp/requestLedger.js +76 -3
  182. package/dist/mcp/requestLedger.js.map +1 -1
  183. package/dist/mcp/seriesEvidence.js +16 -7
  184. package/dist/mcp/seriesEvidence.js.map +1 -1
  185. package/dist/mcp/terminate.js +193 -0
  186. package/dist/mcp/terminate.js.map +1 -0
  187. package/dist/mcp/throttleRetry.js +71 -7
  188. package/dist/mcp/throttleRetry.js.map +1 -1
  189. package/dist/redaction/knownStrings.js +34 -0
  190. package/dist/redaction/knownStrings.js.map +1 -1
  191. package/dist/tool-providers/index.js +12 -1
  192. package/dist/tool-providers/index.js.map +1 -1
  193. package/dist/tools/mcpClientUse.js +225 -0
  194. package/dist/tools/mcpClientUse.js.map +1 -0
  195. package/dist/tools/toolSessions.js +44 -1
  196. package/dist/tools/toolSessions.js.map +1 -1
  197. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
  198. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  199. package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
  200. package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts.map +1 -1
  201. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  202. package/dist/types/core/Agent.d.ts.map +1 -1
  203. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  204. package/dist/types/core/slots/buildToolsSlot.d.ts +12 -0
  205. package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
  206. package/dist/types/events/payloads.d.ts +41 -0
  207. package/dist/types/events/payloads.d.ts.map +1 -1
  208. package/dist/types/events/registry.d.ts +3 -1
  209. package/dist/types/events/registry.d.ts.map +1 -1
  210. package/dist/types/identity/types.d.ts +7 -3
  211. package/dist/types/identity/types.d.ts.map +1 -1
  212. package/dist/types/index.d.ts +1 -1
  213. package/dist/types/index.d.ts.map +1 -1
  214. package/dist/types/lib/boundedJson.d.ts +14 -7
  215. package/dist/types/lib/boundedJson.d.ts.map +1 -1
  216. package/dist/types/mcp/callLifetime.d.ts.map +1 -1
  217. package/dist/types/mcp/clientPort.d.ts +79 -0
  218. package/dist/types/mcp/clientPort.d.ts.map +1 -0
  219. package/dist/types/mcp/gatewayTransport.d.ts.map +1 -1
  220. package/dist/types/mcp/index.d.ts +9 -1
  221. package/dist/types/mcp/index.d.ts.map +1 -1
  222. package/dist/types/mcp/mcpClient.d.ts +18 -1
  223. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  224. package/dist/types/mcp/mockMcpClient.d.ts.map +1 -1
  225. package/dist/types/mcp/pool/boundTool.d.ts +59 -0
  226. package/dist/types/mcp/pool/boundTool.d.ts.map +1 -0
  227. package/dist/types/mcp/pool/clientSet.d.ts +74 -0
  228. package/dist/types/mcp/pool/clientSet.d.ts.map +1 -0
  229. package/dist/types/mcp/pool/definitions.d.ts +104 -0
  230. package/dist/types/mcp/pool/definitions.d.ts.map +1 -0
  231. package/dist/types/mcp/pool/errors.d.ts +77 -0
  232. package/dist/types/mcp/pool/errors.d.ts.map +1 -0
  233. package/dist/types/mcp/pool/identityKey.d.ts +58 -0
  234. package/dist/types/mcp/pool/identityKey.d.ts.map +1 -0
  235. package/dist/types/mcp/pool/lease.d.ts +37 -0
  236. package/dist/types/mcp/pool/lease.d.ts.map +1 -0
  237. package/dist/types/mcp/pool/listTools.d.ts +34 -0
  238. package/dist/types/mcp/pool/listTools.d.ts.map +1 -0
  239. package/dist/types/mcp/pool/mcpClientPool.d.ts +122 -0
  240. package/dist/types/mcp/pool/mcpClientPool.d.ts.map +1 -0
  241. package/dist/types/mcp/pool/options.d.ts +184 -0
  242. package/dist/types/mcp/pool/options.d.ts.map +1 -0
  243. package/dist/types/mcp/pool/plan.d.ts +78 -0
  244. package/dist/types/mcp/pool/plan.d.ts.map +1 -0
  245. package/dist/types/mcp/pool/pool.d.ts +308 -0
  246. package/dist/types/mcp/pool/pool.d.ts.map +1 -0
  247. package/dist/types/mcp/pool/pooledClient.d.ts +94 -0
  248. package/dist/types/mcp/pool/pooledClient.d.ts.map +1 -0
  249. package/dist/types/mcp/pool/record.d.ts +81 -0
  250. package/dist/types/mcp/pool/record.d.ts.map +1 -0
  251. package/dist/types/mcp/pool/sessionEnded.d.ts +25 -0
  252. package/dist/types/mcp/pool/sessionEnded.d.ts.map +1 -0
  253. package/dist/types/mcp/pool/work.d.ts +117 -0
  254. package/dist/types/mcp/pool/work.d.ts.map +1 -0
  255. package/dist/types/mcp/requestGuard.d.ts +71 -0
  256. package/dist/types/mcp/requestGuard.d.ts.map +1 -0
  257. package/dist/types/mcp/requestLedger.d.ts +35 -1
  258. package/dist/types/mcp/requestLedger.d.ts.map +1 -1
  259. package/dist/types/mcp/seriesEvidence.d.ts +10 -6
  260. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
  261. package/dist/types/mcp/terminate.d.ts +95 -0
  262. package/dist/types/mcp/terminate.d.ts.map +1 -0
  263. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  264. package/dist/types/mcp/types.d.ts +85 -7
  265. package/dist/types/mcp/types.d.ts.map +1 -1
  266. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  267. package/dist/types/tool-providers/index.d.ts +2 -2
  268. package/dist/types/tool-providers/index.d.ts.map +1 -1
  269. package/dist/types/tools/mcpClientUse.d.ts +60 -0
  270. package/dist/types/tools/mcpClientUse.d.ts.map +1 -0
  271. package/dist/types/tools/toolProvider.d.ts +16 -0
  272. package/dist/types/tools/toolProvider.d.ts.map +1 -1
  273. package/dist/types/tools/toolSessions.d.ts +41 -0
  274. package/dist/types/tools/toolSessions.d.ts.map +1 -1
  275. package/package.json +3 -3
@@ -0,0 +1,183 @@
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 type { MemoryIdentity } from '../../memory/identity/types.js';
14
+ import { type McpReplayOptions } from '../replay.js';
15
+ import type { RetryOnThrottle } from '../throttleRetry.js';
16
+ import type { McpJsonSchemaValidator, McpSdk, McpTransport } from '../types.js';
17
+ import type { McpPoolReport } from './record.js';
18
+ import type { PoolClientOpener } from './plan.js';
19
+ /** The identity a pool keys a client by: `{ tenant?, principal?, conversationId }`. */
20
+ export type McpPoolIdentity = MemoryIdentity;
21
+ /** What a conversation's tool list may be shared under: two names the app vouches for. */
22
+ export interface McpPoolShareContext {
23
+ /**
24
+ * What the transport hides in its code — a signer's role, the credentials of
25
+ * an AWS client, a custom `fetch`. Hashed into the context, never recorded.
26
+ */
27
+ readonly configuration: string;
28
+ /**
29
+ * What the server's tool visibility depends on — a role and a policy version
30
+ * (`'analyst@policy-7'`). A version in the name reaches a new entry without
31
+ * `permissionsChanged`, for conversations that already have a client too:
32
+ * their tools are listed again under the new name, and a tool bound under the
33
+ * old one is refused before it is sent. Hashed into the context, never
34
+ * recorded.
35
+ */
36
+ readonly authorization: string;
37
+ }
38
+ /**
39
+ * Share tool definitions between conversations — declared by the app, checked by
40
+ * the pool. `share` is asked for every conversation before anything opens, and
41
+ * again at every listing, every call and every send gate after that, so a
42
+ * changed answer takes effect at the next one; it must be synchronous and
43
+ * cheap. A listing's answer is kept only if the names still give the context it
44
+ * was listed for when it arrives — otherwise it is dropped and listed again. Return both names, or `undefined` to keep that conversation's list to
45
+ * itself. Conversations share a list only when the transport's comparable
46
+ * data, both names and the tenant are all equal. A `share` that throws refuses
47
+ * the open (`init-failed`) or, for a conversation that already has a client,
48
+ * that listing or call (`binding-changed`) — its error as `cause`. Never share
49
+ * a server whose list follows the session (one that unlocks tools as a
50
+ * conversation goes on).
51
+ */
52
+ export interface McpPoolDefinitionSharing {
53
+ readonly share: (identity: McpPoolIdentity) => McpPoolShareContext | undefined;
54
+ }
55
+ /** Options for {@link mcpClientPool}. */
56
+ export interface McpClientPoolOptions {
57
+ /** The server's name: every tool's `source`, the provider's id, and the record. */
58
+ readonly name: string;
59
+ /**
60
+ * The transport each client is opened over. A FUNCTION of the identity is
61
+ * preferred: it is called before each client opens (and again for every
62
+ * replacement) with the identity the client is for, so each client gets a
63
+ * transport — and a session map — of its own, and a provider can vend THAT
64
+ * user's credential. One shared object serves every client; a shared
65
+ * `'reuse'` runtime transport then needs `maxClients + maxEnding` at or below
66
+ * its 256 remembered connections.
67
+ */
68
+ readonly transport: McpTransport | ((identity: McpPoolIdentity) => McpTransport);
69
+ /** Open clients — opening, busy or idle. Default 64. */
70
+ readonly maxClients?: number;
71
+ /** Open clients for one principal (one tenant's principal). Default 8. */
72
+ readonly maxClientsPerPrincipal?: number;
73
+ /** Clients being ended at once, until each ending's work has settled. Default 8. */
74
+ readonly maxEnding?: number;
75
+ /**
76
+ * Opens, listings, calls and endings outstanding on any client, each from
77
+ * its admission until its work has settled — not merely until its caller was
78
+ * answered. Default 256. Size it above `maxEnding`.
79
+ */
80
+ readonly maxOperations?: number;
81
+ /** One open per conversation, under this ceiling. Default 30 000 ms. */
82
+ readonly initTimeoutMs?: number;
83
+ /**
84
+ * End a client idle this long, at the next pool interaction (no timer is
85
+ * installed). Default 600 000 ms — below AgentCore Runtime's 900 s idle
86
+ * timeout; set it lower for a runtime configured lower.
87
+ */
88
+ readonly idleMs?: number;
89
+ /** An app lease (`acquire`) is revoked past this. Default 900 000 ms (15 minutes). */
90
+ readonly maxLeaseMs?: number;
91
+ /** A tool list is listed again after this, at the next list. Default 600 000 ms. */
92
+ readonly definitionTtlMs?: number;
93
+ /** `'per-client'` (the default), or the app's declared sharing contract. */
94
+ readonly definitions?: 'per-client' | McpPoolDefinitionSharing;
95
+ /** Refuse an identity without a `principal`. Default `true`. */
96
+ readonly requirePrincipal?: boolean;
97
+ /** Refuse an identity without a `tenant` — for multitenant hosts. Default `false`. */
98
+ readonly requireTenant?: boolean;
99
+ /**
100
+ * What happens outside a run — endings, deferred endings, revoked leases,
101
+ * work that settled after its deadline. Ids and outcomes only. A throwing
102
+ * handler is swallowed and changes nothing.
103
+ */
104
+ readonly onEvent?: (report: McpPoolReport) => void;
105
+ /** Passed to every client: how a tool's result is decoded (`McpClientOptions.resultMode`). */
106
+ readonly resultMode?: 'text' | 'structured' | 'structured-or-json';
107
+ /** Passed to every client: the `initialize` identity. */
108
+ readonly clientInfo?: {
109
+ readonly name: string;
110
+ readonly version: string;
111
+ };
112
+ /** Passed to every client: the 429 retry (`McpClientOptions.retryOnThrottle`). */
113
+ readonly retryOnThrottle?: RetryOnThrottle;
114
+ /**
115
+ * Passed to every client: who may send a tool call again
116
+ * (`McpClientOptions.replay`). Read and checked when the pool is built. The
117
+ * default stays `'compatibility'`. Whatever the policy, the pool's own send
118
+ * gate refuses a pooled request it cannot check (`request-unmatched`).
119
+ */
120
+ readonly replay?: McpReplayOptions;
121
+ /** Passed to every client: the two SDK modules, imported by you (`McpClientOptions.sdk`). */
122
+ readonly sdk?: McpSdk;
123
+ /**
124
+ * Passed to every client: the JSON Schema validator a tool's own output checks
125
+ * use (`McpClientOptions.jsonSchemaValidator`). With `sdk`, give it: a shared
126
+ * definition always runs its own checks, and without a validator a tool that
127
+ * declares an `outputSchema` is refused unsent.
128
+ */
129
+ readonly jsonSchemaValidator?: McpJsonSchemaValidator;
130
+ /** Clock seam — tests drive idle, lease and definition ages without waiting. */
131
+ readonly now?: () => number;
132
+ /** @internal Test seam: how a client is opened (the real path is `openPooledClient`). */
133
+ readonly _open?: PoolClientOpener;
134
+ }
135
+ /** The defaults, named so a test and a docstring cannot drift from the code. */
136
+ export declare const MCP_POOL_DEFAULTS: Readonly<{
137
+ maxClients: 64;
138
+ maxClientsPerPrincipal: 8;
139
+ maxEnding: 8;
140
+ maxOperations: 256;
141
+ initTimeoutMs: 30000;
142
+ idleMs: 600000;
143
+ maxLeaseMs: 900000;
144
+ definitionTtlMs: 600000;
145
+ }>;
146
+ /** At most this many shared definition entries are kept; the least recently used goes first. */
147
+ export declare const MAX_DEFINITION_ENTRIES = 256;
148
+ /** A list longer than this is used by its own client and never shared. */
149
+ export declare const MAX_SHARED_TOOLS = 512;
150
+ /** The pool's settings, read once. */
151
+ export interface PoolSettings {
152
+ readonly name: string;
153
+ readonly transport: (identity: McpPoolIdentity) => McpTransport;
154
+ readonly maxClients: number;
155
+ readonly maxClientsPerPrincipal: number;
156
+ readonly maxEnding: number;
157
+ readonly maxOperations: number;
158
+ readonly initTimeoutMs: number;
159
+ readonly idleMs: number;
160
+ readonly maxLeaseMs: number;
161
+ readonly definitionTtlMs: number;
162
+ readonly share: McpPoolDefinitionSharing['share'] | undefined;
163
+ readonly requirePrincipal: boolean;
164
+ readonly requireTenant: boolean;
165
+ readonly onEvent: ((report: McpPoolReport) => void) | undefined;
166
+ readonly client: {
167
+ readonly resultMode?: McpClientPoolOptions['resultMode'];
168
+ readonly clientInfo?: McpClientPoolOptions['clientInfo'];
169
+ readonly retryOnThrottle?: RetryOnThrottle;
170
+ readonly replay?: McpReplayOptions;
171
+ readonly sdk?: McpSdk;
172
+ readonly jsonSchemaValidator?: McpJsonSchemaValidator;
173
+ };
174
+ readonly now: () => number;
175
+ readonly open: PoolClientOpener | undefined;
176
+ }
177
+ /**
178
+ * Read `options` once.
179
+ *
180
+ * @throws TypeError naming the option, when one is missing, mistyped or out of
181
+ * range, or when `connection` is given — here, when the pool is built.
182
+ */
183
+ export declare function readPoolOptions(options: McpClientPoolOptions): PoolSettings;
@@ -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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"}