agentfootprint 11.4.0 → 12.0.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 (198) hide show
  1. package/CAPABILITIES.md +3 -1
  2. package/dist/adapters/code/agentcore.js +295 -214
  3. package/dist/adapters/code/agentcore.js.map +1 -1
  4. package/dist/adapters/code/agentcoreClient.js +178 -0
  5. package/dist/adapters/code/agentcoreClient.js.map +1 -0
  6. package/dist/adapters/code/agentcoreWire.js +348 -0
  7. package/dist/adapters/code/agentcoreWire.js.map +1 -0
  8. package/dist/adapters/code/fileName.js +100 -0
  9. package/dist/adapters/code/fileName.js.map +1 -0
  10. package/dist/adapters/code/local.js +529 -183
  11. package/dist/adapters/code/local.js.map +1 -1
  12. package/dist/adapters/code/output.js +140 -0
  13. package/dist/adapters/code/output.js.map +1 -0
  14. package/dist/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
  15. package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  16. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +36 -2
  17. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  18. package/dist/adapters/mcp/agentcoreRuntime/transport.js +3 -1
  19. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  20. package/dist/core/codeRunnerTool.js +52 -7
  21. package/dist/core/codeRunnerTool.js.map +1 -1
  22. package/dist/doors/providers.js.map +1 -1
  23. package/dist/esm/adapters/code/agentcore.d.ts +65 -68
  24. package/dist/esm/adapters/code/agentcore.js +293 -212
  25. package/dist/esm/adapters/code/agentcore.js.map +1 -1
  26. package/dist/esm/adapters/code/agentcoreClient.d.ts +193 -0
  27. package/dist/esm/adapters/code/agentcoreClient.js +173 -0
  28. package/dist/esm/adapters/code/agentcoreClient.js.map +1 -0
  29. package/dist/esm/adapters/code/agentcoreWire.d.ts +119 -0
  30. package/dist/esm/adapters/code/agentcoreWire.js +334 -0
  31. package/dist/esm/adapters/code/agentcoreWire.js.map +1 -0
  32. package/dist/esm/adapters/code/fileName.d.ts +43 -0
  33. package/dist/esm/adapters/code/fileName.js +96 -0
  34. package/dist/esm/adapters/code/fileName.js.map +1 -0
  35. package/dist/esm/adapters/code/local.d.ts +91 -12
  36. package/dist/esm/adapters/code/local.js +528 -182
  37. package/dist/esm/adapters/code/local.js.map +1 -1
  38. package/dist/esm/adapters/code/output.d.ts +70 -0
  39. package/dist/esm/adapters/code/output.js +129 -0
  40. package/dist/esm/adapters/code/output.js.map +1 -0
  41. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
  42. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
  43. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  44. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
  45. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +35 -1
  46. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  47. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +4 -2
  48. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  49. package/dist/esm/core/codeRunnerTool.d.ts +15 -3
  50. package/dist/esm/core/codeRunnerTool.js +52 -7
  51. package/dist/esm/core/codeRunnerTool.js.map +1 -1
  52. package/dist/esm/doors/providers.d.ts +1 -1
  53. package/dist/esm/doors/providers.js.map +1 -1
  54. package/dist/esm/events/payloads.d.ts +144 -29
  55. package/dist/esm/index.d.ts +2 -0
  56. package/dist/esm/index.js +5 -0
  57. package/dist/esm/index.js.map +1 -1
  58. package/dist/esm/mcp/callLifetime.d.ts +57 -14
  59. package/dist/esm/mcp/callLifetime.js +67 -19
  60. package/dist/esm/mcp/callLifetime.js.map +1 -1
  61. package/dist/esm/mcp/callMarker.d.ts +43 -0
  62. package/dist/esm/mcp/callMarker.js +69 -0
  63. package/dist/esm/mcp/callMarker.js.map +1 -0
  64. package/dist/esm/mcp/connectionRefusals.js +7 -0
  65. package/dist/esm/mcp/connectionRefusals.js.map +1 -1
  66. package/dist/esm/mcp/index.d.ts +2 -0
  67. package/dist/esm/mcp/index.js +3 -0
  68. package/dist/esm/mcp/index.js.map +1 -1
  69. package/dist/esm/mcp/mcpClient.js +93 -26
  70. package/dist/esm/mcp/mcpClient.js.map +1 -1
  71. package/dist/esm/mcp/replay.d.ts +291 -0
  72. package/dist/esm/mcp/replay.js +405 -0
  73. package/dist/esm/mcp/replay.js.map +1 -0
  74. package/dist/esm/mcp/replayUnavailable.d.ts +68 -0
  75. package/dist/esm/mcp/replayUnavailable.js +87 -0
  76. package/dist/esm/mcp/replayUnavailable.js.map +1 -0
  77. package/dist/esm/mcp/requestLedger.d.ts +115 -32
  78. package/dist/esm/mcp/requestLedger.js +193 -52
  79. package/dist/esm/mcp/requestLedger.js.map +1 -1
  80. package/dist/esm/mcp/seriesEvidence.d.ts +73 -15
  81. package/dist/esm/mcp/seriesEvidence.js +114 -21
  82. package/dist/esm/mcp/seriesEvidence.js.map +1 -1
  83. package/dist/esm/mcp/throttleRetry.d.ts +86 -42
  84. package/dist/esm/mcp/throttleRetry.js +158 -50
  85. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  86. package/dist/esm/mcp/toolResult.d.ts +6 -0
  87. package/dist/esm/mcp/toolResult.js +15 -0
  88. package/dist/esm/mcp/toolResult.js.map +1 -1
  89. package/dist/esm/mcp/types.d.ts +73 -8
  90. package/dist/esm/provider-contract/codeSandbox.d.ts +89 -0
  91. package/dist/esm/provider-contract/codeSandbox.js +119 -0
  92. package/dist/esm/provider-contract/codeSandbox.js.map +1 -0
  93. package/dist/esm/provider-contract/sessionExpired.d.ts +31 -0
  94. package/dist/esm/provider-contract/sessionExpired.js +40 -0
  95. package/dist/esm/provider-contract/sessionExpired.js.map +1 -0
  96. package/dist/esm/provider-contract/types.d.ts +166 -17
  97. package/dist/esm/provider-contract/types.js +9 -0
  98. package/dist/esm/provider-contract/types.js.map +1 -1
  99. package/dist/esm/redaction/knownStrings.js +16 -0
  100. package/dist/esm/redaction/knownStrings.js.map +1 -1
  101. package/dist/esm/tool-providers/index.d.ts +2 -2
  102. package/dist/esm/tool-providers/index.js +4 -0
  103. package/dist/esm/tool-providers/index.js.map +1 -1
  104. package/dist/esm/tools/requestEvidence.js +60 -0
  105. package/dist/esm/tools/requestEvidence.js.map +1 -1
  106. package/dist/index.js +12 -4
  107. package/dist/index.js.map +1 -1
  108. package/dist/mcp/callLifetime.js +66 -18
  109. package/dist/mcp/callLifetime.js.map +1 -1
  110. package/dist/mcp/callMarker.js +74 -0
  111. package/dist/mcp/callMarker.js.map +1 -0
  112. package/dist/mcp/connectionRefusals.js +7 -0
  113. package/dist/mcp/connectionRefusals.js.map +1 -1
  114. package/dist/mcp/index.js +5 -1
  115. package/dist/mcp/index.js.map +1 -1
  116. package/dist/mcp/mcpClient.js +91 -24
  117. package/dist/mcp/mcpClient.js.map +1 -1
  118. package/dist/mcp/replay.js +415 -0
  119. package/dist/mcp/replay.js.map +1 -0
  120. package/dist/mcp/replayUnavailable.js +92 -0
  121. package/dist/mcp/replayUnavailable.js.map +1 -0
  122. package/dist/mcp/requestLedger.js +193 -52
  123. package/dist/mcp/requestLedger.js.map +1 -1
  124. package/dist/mcp/seriesEvidence.js +116 -22
  125. package/dist/mcp/seriesEvidence.js.map +1 -1
  126. package/dist/mcp/throttleRetry.js +160 -51
  127. package/dist/mcp/throttleRetry.js.map +1 -1
  128. package/dist/mcp/toolResult.js +17 -1
  129. package/dist/mcp/toolResult.js.map +1 -1
  130. package/dist/provider-contract/codeSandbox.js +125 -0
  131. package/dist/provider-contract/codeSandbox.js.map +1 -0
  132. package/dist/provider-contract/sessionExpired.js +44 -0
  133. package/dist/provider-contract/sessionExpired.js.map +1 -0
  134. package/dist/provider-contract/types.js +12 -1
  135. package/dist/provider-contract/types.js.map +1 -1
  136. package/dist/redaction/knownStrings.js +16 -0
  137. package/dist/redaction/knownStrings.js.map +1 -1
  138. package/dist/tool-providers/index.js +5 -1
  139. package/dist/tool-providers/index.js.map +1 -1
  140. package/dist/tools/requestEvidence.js +60 -0
  141. package/dist/tools/requestEvidence.js.map +1 -1
  142. package/dist/types/adapters/code/agentcore.d.ts +65 -68
  143. package/dist/types/adapters/code/agentcore.d.ts.map +1 -1
  144. package/dist/types/adapters/code/agentcoreClient.d.ts +194 -0
  145. package/dist/types/adapters/code/agentcoreClient.d.ts.map +1 -0
  146. package/dist/types/adapters/code/agentcoreWire.d.ts +120 -0
  147. package/dist/types/adapters/code/agentcoreWire.d.ts.map +1 -0
  148. package/dist/types/adapters/code/fileName.d.ts +44 -0
  149. package/dist/types/adapters/code/fileName.d.ts.map +1 -0
  150. package/dist/types/adapters/code/local.d.ts +91 -12
  151. package/dist/types/adapters/code/local.d.ts.map +1 -1
  152. package/dist/types/adapters/code/output.d.ts +71 -0
  153. package/dist/types/adapters/code/output.d.ts.map +1 -0
  154. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
  155. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  156. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
  157. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
  158. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  159. package/dist/types/core/codeRunnerTool.d.ts +15 -3
  160. package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
  161. package/dist/types/doors/providers.d.ts +1 -1
  162. package/dist/types/doors/providers.d.ts.map +1 -1
  163. package/dist/types/events/payloads.d.ts +144 -29
  164. package/dist/types/events/payloads.d.ts.map +1 -1
  165. package/dist/types/index.d.ts +2 -0
  166. package/dist/types/index.d.ts.map +1 -1
  167. package/dist/types/mcp/callLifetime.d.ts +57 -14
  168. package/dist/types/mcp/callLifetime.d.ts.map +1 -1
  169. package/dist/types/mcp/callMarker.d.ts +44 -0
  170. package/dist/types/mcp/callMarker.d.ts.map +1 -0
  171. package/dist/types/mcp/index.d.ts +2 -0
  172. package/dist/types/mcp/index.d.ts.map +1 -1
  173. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  174. package/dist/types/mcp/replay.d.ts +292 -0
  175. package/dist/types/mcp/replay.d.ts.map +1 -0
  176. package/dist/types/mcp/replayUnavailable.d.ts +69 -0
  177. package/dist/types/mcp/replayUnavailable.d.ts.map +1 -0
  178. package/dist/types/mcp/requestLedger.d.ts +115 -32
  179. package/dist/types/mcp/requestLedger.d.ts.map +1 -1
  180. package/dist/types/mcp/seriesEvidence.d.ts +73 -15
  181. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
  182. package/dist/types/mcp/throttleRetry.d.ts +86 -42
  183. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  184. package/dist/types/mcp/toolResult.d.ts +6 -0
  185. package/dist/types/mcp/toolResult.d.ts.map +1 -1
  186. package/dist/types/mcp/types.d.ts +73 -8
  187. package/dist/types/mcp/types.d.ts.map +1 -1
  188. package/dist/types/provider-contract/codeSandbox.d.ts +90 -0
  189. package/dist/types/provider-contract/codeSandbox.d.ts.map +1 -0
  190. package/dist/types/provider-contract/sessionExpired.d.ts +32 -0
  191. package/dist/types/provider-contract/sessionExpired.d.ts.map +1 -0
  192. package/dist/types/provider-contract/types.d.ts +166 -17
  193. package/dist/types/provider-contract/types.d.ts.map +1 -1
  194. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  195. package/dist/types/tool-providers/index.d.ts +2 -2
  196. package/dist/types/tool-providers/index.d.ts.map +1 -1
  197. package/dist/types/tools/requestEvidence.d.ts.map +1 -1
  198. package/package.json +1 -1
@@ -0,0 +1,415 @@
1
+ "use strict";
2
+ /**
3
+ * replay — who may send an MCP tool call again, and what is known of what each
4
+ * attempt did: two facts, decided apart and recorded apart.
5
+ *
6
+ * Pattern: a declaration read once + one permission rule + one accumulator.
7
+ * Role: Layer-3 tool transport. `mcpClient({ replay })` reads the app's
8
+ * declaration (`replayDeclarationOf`) when the client is built. The
9
+ * call's retry series (`throttleRetry.ts` · `Series`) asks `permit`
10
+ * before every repeat and records the answer beside the attempt;
11
+ * `SeriesKnowledge` carries what is known of the series' effect from
12
+ * one attempt to the next.
13
+ *
14
+ * ── THE LAW ──────────────────────────────────────────────────────────────────
15
+ * PERMISSION to repeat comes only from the app: the (server, tool) pairs it
16
+ * declares — the server is the client the declaration is given to — and the
17
+ * failure kinds each tool may be repeated on. Never from the model, a tool's
18
+ * description or a server's annotations (`readOnlyHint`): nothing here reads
19
+ * them. It is configuration, read once when the client is built — never a
20
+ * per-call question.
21
+ *
22
+ * KNOWLEDGE of whether an attempt ran comes only from the record and from an
23
+ * established service guarantee. No reply this library reads is one. A 429 is
24
+ * not: RFC 6585 §4 defines it as rate limiting, and `Retry-After` says when to
25
+ * ask again, not that asking is safe. AgentCore Runtime's session-busy body is
26
+ * not either: AWS documents a retryable conflict while a session starts or
27
+ * stops, and the body is matched by its code and words, which a server behind
28
+ * the runtime can send after it ran the call. So every attempt that was sent
29
+ * and did not complete is `unknown`; `none` is only a request never sent. A
30
+ * vendor's own SDK may retry its own 429s because the vendor documents its own
31
+ * service; a generic MCP client cannot assume that of an arbitrary server.
32
+ *
33
+ * Neither is read from the other: a permission never makes an effect known,
34
+ * and an effect never grants a permission.
35
+ *
36
+ * ── WHAT A REPEAT IS ─────────────────────────────────────────────────────────
37
+ * The same validated, authorized request sent again: the same body — the same
38
+ * arguments — to the same server, in the same session, as the same identity.
39
+ * Nothing is re-planned. A credential the library vends, or a signature, is
40
+ * made afresh for each attempt (signatures expire), for that same identity.
41
+ *
42
+ * ── THE POLICIES ─────────────────────────────────────────────────────────────
43
+ * 'compatibility' — the default, kept in 12.0: today's behaviour by name. A
44
+ * 429 is repeated for every tool, on the ASSUMPTION that the server
45
+ * refused it before running it. Each such repeat records that
46
+ * assumption; the attempt's effect stays `unknown`, and the caller sees
47
+ * the error it always did. It gains none of the strict policy's
48
+ * guarantees: it never establishes that answers are seen or that
49
+ * requests are matched to their calls.
50
+ * 'app-authorized' — opt-in, by name only: a 429 or a network failure is
51
+ * repeated only when the app's entry for the tool names it. What the
52
+ * caller sees follows footprintjs's law
53
+ * (`RequestReplay` · `uncertain`, `callLifetime.ts`): a received refusal
54
+ * or error keeps the server's error as it came, its effect still
55
+ * `unknown`; a call that genuinely lacked an answer somewhere — an
56
+ * attempt with no response, or a request accepted over HTTP whose
57
+ * JSON-RPC answer never came — and then fails, fails with
58
+ * `UnknownEffectError`, its final error the cause. That needs each
59
+ * request matched to its call and each answer seen; a connection that
60
+ * cannot give both refuses the tool call before its request is sent
61
+ * (`replayUnavailable.ts`), so the contract never silently weakens. It
62
+ * never falls back to 'compatibility', and nothing chooses it from the
63
+ * transport.
64
+ *
65
+ * Under both, the adapter the app chose retries its own refusal within the
66
+ * budget — AgentCore's session-busy reply — as the ADAPTER's policy, on an
67
+ * assumption it records the same way (`permission: { by: 'adapter', assumes }`),
68
+ * never as evidence. And THE SIDE-EFFECT GUARD holds: a tool the app declares
69
+ * as making changes is never repeated automatically unless the server is
70
+ * declared to deduplicate by an idempotency key the call carries —
71
+ * footprintjs's law, a retry of an effect without a key can apply it twice. A
72
+ * key protects only when the server uses it; the library cannot check that.
73
+ *
74
+ * The protocol's own requests (`initialize`, `tools/list`, notifications) run
75
+ * no tool. The declaration does not govern them, and a 429 on one is asked
76
+ * again under both policies, as it always was. They file no record.
77
+ */
78
+ Object.defineProperty(exports, "__esModule", { value: true });
79
+ exports.RequestReplay = exports.SeriesKnowledge = exports.permit = exports.thrownFailure = exports.replayTargetOf = exports.needsSeries = exports.replayDeclarationOf = exports.COMPATIBILITY = void 0;
80
+ const footprintjs_1 = require("footprintjs");
81
+ /** @internal No declaration: the compatibility policy, no tool named. */
82
+ exports.COMPATIBILITY = Object.freeze({
83
+ policy: 'compatibility',
84
+ tools: new Map(),
85
+ });
86
+ const POLICIES = new Set(['app-authorized', 'compatibility']);
87
+ const KINDS = new Set(['throttle', 'network']);
88
+ /**
89
+ * @internal `options` read as a declaration — `undefined` is the compatibility
90
+ * policy with nothing named.
91
+ *
92
+ * @throws TypeError naming the field, never echoing a value, for anything the
93
+ * rule cannot mean: an unknown field, a policy or kind it does not know, an
94
+ * argument name that is not one.
95
+ */
96
+ function replayDeclarationOf(options, where) {
97
+ if (options === undefined)
98
+ return exports.COMPATIBILITY;
99
+ const read = new DeclarationReader(`${where}: \`replay\``);
100
+ const top = read.record(options, '', ['policy', 'tools', 'deduplicates']);
101
+ const policy = top.policy === undefined ? 'compatibility' : read.policy(top.policy);
102
+ const tools = new Map();
103
+ if (top.tools !== undefined) {
104
+ const named = read.record(top.tools, '.tools', undefined);
105
+ for (const [tool, entry] of Object.entries(named)) {
106
+ if (tool.length === 0)
107
+ read.refuse('.tools', 'tool names that are not empty');
108
+ tools.set(tool, read.tool(entry, tool));
109
+ }
110
+ }
111
+ const keyArgument = top.deduplicates === undefined ? undefined : read.deduplication(top.deduplicates);
112
+ return Object.freeze({
113
+ policy,
114
+ tools,
115
+ ...(keyArgument !== undefined && { keyArgument }),
116
+ });
117
+ }
118
+ exports.replayDeclarationOf = replayDeclarationOf;
119
+ /** Reads one declaration, refusing by field what it cannot mean. */
120
+ class DeclarationReader {
121
+ where;
122
+ constructor(where) {
123
+ this.where = where;
124
+ }
125
+ /** A plain object, its own keys within `allowed` (any key when `undefined`). */
126
+ record(value, at, allowed) {
127
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
128
+ this.refuse(at, 'an object');
129
+ }
130
+ const record = value;
131
+ if (allowed !== undefined) {
132
+ for (const key of Object.keys(record)) {
133
+ if (!allowed.includes(key)) {
134
+ this.refuse(at, `an object with only ${allowed.map((k) => `\`${k}\``).join(', ')}`);
135
+ }
136
+ }
137
+ }
138
+ return record;
139
+ }
140
+ policy(value) {
141
+ if (typeof value === 'string' && POLICIES.has(value))
142
+ return value;
143
+ return this.refuse('.policy', "'app-authorized' or 'compatibility'");
144
+ }
145
+ tool(value, tool) {
146
+ const at = `.tools[${JSON.stringify(tool)}]`;
147
+ const entry = this.record(value, at, ['on', 'changes']);
148
+ const on = new Set();
149
+ if (entry.on !== undefined) {
150
+ if (!Array.isArray(entry.on))
151
+ this.refuse(`${at}.on`, "an array of 'throttle' or 'network'");
152
+ for (const kind of entry.on) {
153
+ if (typeof kind !== 'string' || !KINDS.has(kind)) {
154
+ this.refuse(`${at}.on`, "an array of 'throttle' or 'network'");
155
+ }
156
+ on.add(kind);
157
+ }
158
+ }
159
+ if (entry.changes !== undefined && typeof entry.changes !== 'boolean') {
160
+ this.refuse(`${at}.changes`, 'a boolean');
161
+ }
162
+ return Object.freeze({ on, changes: entry.changes === true });
163
+ }
164
+ deduplication(value) {
165
+ const declared = this.record(value, '.deduplicates', ['argument']);
166
+ const { argument } = declared;
167
+ if (typeof argument === 'string' &&
168
+ argument.length >= 1 &&
169
+ argument.length <= 128 &&
170
+ !hasControl(argument)) {
171
+ return argument;
172
+ }
173
+ return this.refuse('.deduplicates.argument', 'an argument name of 1–128 characters with no control character');
174
+ }
175
+ refuse(at, wanted) {
176
+ throw new TypeError(`${this.where}${at} must be ${wanted}.`);
177
+ }
178
+ }
179
+ /**
180
+ * @internal Whether the declaration needs a retry series even with the 429
181
+ * rule off (`retryOnThrottle: false`): a tool declared repeatable on
182
+ * `'network'`, or the `'app-authorized'` policy — its record and its "may have
183
+ * run" rest on the series.
184
+ */
185
+ function needsSeries(declaration) {
186
+ if (declaration.policy === 'app-authorized')
187
+ return true;
188
+ for (const entry of declaration.tools.values())
189
+ if (entry.on.has('network'))
190
+ return true;
191
+ return false;
192
+ }
193
+ exports.needsSeries = needsSeries;
194
+ const PROTOCOL = Object.freeze({ kind: 'protocol' });
195
+ /** A request that may be a tool call and names no tool the rule can read: no entry applies. */
196
+ const UNNAMED_TOOL = Object.freeze({ kind: 'tool', keyCarried: false });
197
+ /**
198
+ * @internal `body` — the request exactly as it will be sent — read as a
199
+ * target. A declaration that names nothing under `'compatibility'` decides the
200
+ * same for every request, so its bodies are never parsed.
201
+ */
202
+ function replayTargetOf(body, declaration) {
203
+ if (declaration.policy === 'compatibility' && declaration.tools.size === 0)
204
+ return UNNAMED_TOOL;
205
+ if (body === undefined || body === null)
206
+ return PROTOCOL;
207
+ if (typeof body !== 'string')
208
+ return UNNAMED_TOOL;
209
+ let message;
210
+ try {
211
+ message = JSON.parse(body);
212
+ }
213
+ catch {
214
+ return UNNAMED_TOOL;
215
+ }
216
+ if (Array.isArray(message))
217
+ return message.some(isToolCall) ? UNNAMED_TOOL : PROTOCOL;
218
+ if (!isToolCall(message))
219
+ return PROTOCOL;
220
+ const params = message.params;
221
+ if (!isRecord(params))
222
+ return UNNAMED_TOOL;
223
+ const { name, arguments: args } = params;
224
+ const { keyArgument } = declaration;
225
+ return {
226
+ kind: 'tool',
227
+ ...(typeof name === 'string' && { name }),
228
+ keyCarried: keyArgument !== undefined && carriesKey(args, keyArgument),
229
+ };
230
+ }
231
+ exports.replayTargetOf = replayTargetOf;
232
+ function isToolCall(message) {
233
+ return isRecord(message) && message.method === 'tools/call';
234
+ }
235
+ /** The arguments hold a key under `argument`: a non-empty string. The server judges the rest. */
236
+ function carriesKey(args, argument) {
237
+ if (!isRecord(args) || !Object.prototype.hasOwnProperty.call(args, argument))
238
+ return false;
239
+ const key = args[argument];
240
+ return typeof key === 'string' && key.length > 0;
241
+ }
242
+ function isRecord(value) {
243
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
244
+ }
245
+ /** @internal A thrown failure the rule can read: footprintjs's `network` category, or nothing. */
246
+ function thrownFailure(error) {
247
+ return (0, footprintjs_1.errorCategory)(error) === 'network' ? { kind: 'network' } : undefined;
248
+ }
249
+ exports.thrownFailure = thrownFailure;
250
+ /**
251
+ * @internal THE rule: may the series send `target` again after `failure`?
252
+ * Asked before every repeat; the budget is asked after it.
253
+ */
254
+ function permit(declaration, target, failure) {
255
+ if (target.kind === 'protocol') {
256
+ // No tool runs: a refusal is asked again as it always was, a failure is not.
257
+ return failure.kind === 'network' ? NOT_RETRYABLE : REPEAT_PROTOCOL;
258
+ }
259
+ const entry = target.name === undefined ? undefined : declaration.tools.get(target.name);
260
+ // The side-effect guard comes first, under every policy and every permission.
261
+ if (entry?.changes === true && (declaration.keyArgument === undefined || !target.keyCarried)) {
262
+ return CHANGES_WITHOUT_KEY;
263
+ }
264
+ const keyed = entry?.changes === true;
265
+ if (failure.assumes !== undefined) {
266
+ return repeat({ by: 'adapter', assumes: failure.assumes }, keyed);
267
+ }
268
+ if (failure.kind !== 'session-busy' && entry?.on.has(failure.kind) === true) {
269
+ return repeat({ by: 'declaration', on: failure.kind }, keyed);
270
+ }
271
+ if (failure.kind === 'throttle' && declaration.policy === 'compatibility') {
272
+ return repeat({ by: 'compatibility', assumes: 'refused-before-execution' }, keyed);
273
+ }
274
+ return failure.kind === 'throttle' ? NOT_PERMITTED : NOT_RETRYABLE;
275
+ }
276
+ exports.permit = permit;
277
+ const REPEAT_PROTOCOL = Object.freeze({ repeat: true });
278
+ const NOT_RETRYABLE = Object.freeze({ repeat: false, declined: 'not-retryable' });
279
+ const NOT_PERMITTED = Object.freeze({ repeat: false, declined: 'not-permitted' });
280
+ const CHANGES_WITHOUT_KEY = Object.freeze({
281
+ repeat: false,
282
+ declined: 'changes-without-key',
283
+ });
284
+ function repeat(permission, deduplicated) {
285
+ return {
286
+ repeat: true,
287
+ permission: Object.freeze({ ...permission, ...(deduplicated && { deduplicated: true }) }),
288
+ };
289
+ }
290
+ // ─── What is known of a series' effect ───────────────────────────────
291
+ /**
292
+ * @internal What is known of a whole series' effect, one attempt at a time.
293
+ * Uncertainty survives: once any attempt is `unknown`, the series is, whatever
294
+ * later attempts show — a proven refusal does not resolve it, and a success
295
+ * does not prove the operation happened only once. Evidence that something ran
296
+ * (`applied`) is never erased by a later failure.
297
+ */
298
+ class SeriesKnowledge {
299
+ unknown = false;
300
+ applied = false;
301
+ note(effect) {
302
+ if (effect === 'unknown')
303
+ this.unknown = true;
304
+ else if (effect === 'applied')
305
+ this.applied = true;
306
+ }
307
+ get effect() {
308
+ if (this.unknown)
309
+ return 'unknown';
310
+ return this.applied ? 'applied' : 'none';
311
+ }
312
+ }
313
+ exports.SeriesKnowledge = SeriesKnowledge;
314
+ /**
315
+ * @internal One `tools/call` request's replay facts, shared by the series that
316
+ * sends it, the ledger that watches its answer, and the call that waits for it
317
+ * — the ledger hands all three the same object (`requestLedger.ts`).
318
+ *
319
+ * TWO LAYERS, KEPT APART. The series sees HTTP: whether an attempt got a
320
+ * response at all, and the status of the one it delivered. A response is not
321
+ * the MCP call's answer — a 202, or a stream, can be accepted and never carry
322
+ * it — so the ledger watches the connection's incoming messages for the
323
+ * JSON-RPC response to THIS request's id. And "its effect is unknown" is not
324
+ * "it lacked an answer": a received 429 or error is an answer whose effect is
325
+ * unknown.
326
+ *
327
+ * Each fact is written once, by its owner: the series (what it sent, whether an
328
+ * attempt lacked any response, what it delivered, the policy), the ledger (the
329
+ * logical answer), the call (how it settled).
330
+ */
331
+ class RequestReplay {
332
+ id;
333
+ requests = 0;
334
+ appAuthorized = false;
335
+ attemptUnanswered = false;
336
+ delivered;
337
+ logical;
338
+ settled;
339
+ failedAsMayHaveRun = false;
340
+ /**
341
+ * @param id the request's JSON-RPC id, how its answer is found.
342
+ * @param watched whether the connection's incoming messages are observed —
343
+ * without that, the logical layer is unknown and never decides anything.
344
+ */
345
+ constructor(id, watched) {
346
+ this.id = id;
347
+ this.logical = watched ? 'awaited' : 'unwatched';
348
+ }
349
+ /** The series sent the request once more. */
350
+ sentOne() {
351
+ this.requests += 1;
352
+ }
353
+ /** The series runs under the `'app-authorized'` policy. */
354
+ appAuthorizedPolicy() {
355
+ this.appAuthorized = true;
356
+ }
357
+ /**
358
+ * The series: an attempt genuinely lacked an answer — no response arrived
359
+ * (a lost connection, a timeout, a cut). A received refusal is never this.
360
+ */
361
+ noAnswer() {
362
+ this.attemptUnanswered = true;
363
+ }
364
+ /** The series handed the MCP SDK a response with this status. */
365
+ deliveredStatus(status) {
366
+ this.delivered = status;
367
+ }
368
+ /** The ledger: the JSON-RPC response to this request's id arrived. */
369
+ answered() {
370
+ if (this.logical === 'awaited')
371
+ this.logical = 'answered';
372
+ }
373
+ /** The call settled; `mayHaveRun` when it failed as "may have run". The first word stands. */
374
+ settle(verdict, mayHaveRun) {
375
+ if (this.settled !== undefined)
376
+ return;
377
+ this.settled = verdict;
378
+ this.failedAsMayHaveRun = mayHaveRun;
379
+ }
380
+ get sent() {
381
+ return this.requests;
382
+ }
383
+ /**
384
+ * Under `'app-authorized'`, a call that does not complete fails as "may have
385
+ * run" when the call genuinely lacked an answer somewhere: an attempt got no
386
+ * response, or the HTTP layer accepted the request (a 2xx) and the JSON-RPC
387
+ * response never came. A chain of received refusals and errors is an answer
388
+ * throughout: it keeps the server's error.
389
+ */
390
+ get uncertain() {
391
+ return this.appAuthorized && (this.attemptUnanswered || this.acceptedWithoutAnswer);
392
+ }
393
+ /** The HTTP layer took the request (2xx), and the logical answer never arrived. */
394
+ get acceptedWithoutAnswer() {
395
+ const status = this.delivered;
396
+ return this.logical === 'awaited' && status !== undefined && status >= 200 && status < 300;
397
+ }
398
+ get verdict() {
399
+ return this.settled;
400
+ }
401
+ get mayHaveRun() {
402
+ return this.failedAsMayHaveRun;
403
+ }
404
+ }
405
+ exports.RequestReplay = RequestReplay;
406
+ /** Whether `text` holds a control character (C0, DEL or C1). */
407
+ function hasControl(text) {
408
+ for (let i = 0; i < text.length; i++) {
409
+ const code = text.charCodeAt(i);
410
+ if (code < 0x20 || (code >= 0x7f && code <= 0x9f))
411
+ return true;
412
+ }
413
+ return false;
414
+ }
415
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/mcp/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /**
3
+ * replayUnavailable — when a connection cannot keep the `'app-authorized'`
4
+ * contract, a tool call under it is refused BEFORE its request is sent, and the
5
+ * error says why.
6
+ *
7
+ * Pattern: a readiness rule + one typed refusal.
8
+ * Role: Under `'app-authorized'`, a call that genuinely lacked an answer and
9
+ * then fails is raised as "may have run" (`callLifetime.ts`). That
10
+ * rests on two things the library must ESTABLISH for every call,
11
+ * never assume:
12
+ *
13
+ * 1. ITS REQUEST IS MATCHED to the call, by the call's private marker, taken
14
+ * at the transport's `send` (`callMarker.ts`, `requestLedger.ts`).
15
+ * - `'requests-unwatched'`: the library cannot watch this transport's
16
+ * `send` at all (stdio, or a transport that refuses the wrap).
17
+ * - `'request-unmatched'`: a request reached `send` without its call's
18
+ * marker (an SDK that rebuilt the params and dropped `_meta`), so it
19
+ * cannot be tied to any call. Checked on every `tools/call`, so a match
20
+ * lost after the connection initialized is refused too.
21
+ * 2. ITS ANSWER IS SEEN: the JSON-RPC response to the request's id, read as
22
+ * it arrives. This is checked once the connection is initialized: the
23
+ * `initialize` answer must have passed the library's observer.
24
+ * - `'answers-unobserved'`: it did not. An MCP SDK whose `connect`
25
+ * REPLACES the transport's `onmessage` handler instead of keeping it
26
+ * leaves the observer out. SDK 1.10's `Protocol.connect` does, when
27
+ * run; reading the source finds the same through 1.13. The rule tests
28
+ * the behaviour, never a version number.
29
+ *
30
+ * Without either, a request the server accepted and never answered would reach
31
+ * the caller as a plain timeout: the strict contract, silently weakened. So the
32
+ * tool call is refused instead, and its request is not sent. Only tool
33
+ * invocations (`tools/call`) are refused: connecting (`initialize`) and listing
34
+ * tools ran before them and may already have reached the server (on `stdio`,
35
+ * the server process has started). The policy never falls back to
36
+ * `'compatibility'`, and a refused request is never sent again to recover its
37
+ * match. `'compatibility'` asks none of this and keeps its behaviour.
38
+ */
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.unavailableBeforeSending = exports.McpReplayUnavailableError = void 0;
41
+ /** The fixed sentence each reason reads as. Never an argument, a header or an answer. */
42
+ const BECAUSE = {
43
+ 'requests-unwatched': "the library cannot watch this transport's requests, so it cannot match a request to its call",
44
+ 'answers-unobserved': "this connection's answers do not pass the library's observer: the MCP SDK replaced the " +
45
+ "transport's message handler when it connected",
46
+ 'request-unmatched': "the request reached the transport without its call's marker: the MCP SDK rebuilt the " +
47
+ "request's params",
48
+ };
49
+ /**
50
+ * A tool call refused before its request was sent, because this connection
51
+ * cannot keep the `'app-authorized'` replay contract (`reason`). The tool
52
+ * request never reached the server; connecting and listing tools may have.
53
+ * Names the server and the tool, never an argument.
54
+ */
55
+ class McpReplayUnavailableError extends Error {
56
+ reason;
57
+ server;
58
+ tool;
59
+ code = 'ERR_MCP_REPLAY_UNAVAILABLE';
60
+ /**
61
+ * This tool request was not sent: the refusal came before it left the
62
+ * client. It says nothing of the connection: `initialize` and `tools/list`
63
+ * ran before it, and on `stdio` the server process was started.
64
+ */
65
+ sent = false;
66
+ constructor(reason, server, tool) {
67
+ super(`mcpClient[${server}]: the call to '${tool}' was not sent. The 'app-authorized' replay ` +
68
+ `policy needs each request matched to its call and each answer seen, and ` +
69
+ `${BECAUSE[reason]}.`);
70
+ this.reason = reason;
71
+ this.server = server;
72
+ this.tool = tool;
73
+ this.name = 'McpReplayUnavailableError';
74
+ }
75
+ }
76
+ exports.McpReplayUnavailableError = McpReplayUnavailableError;
77
+ /**
78
+ * Why a connection cannot take a call under `'app-authorized'` before anything
79
+ * is sent — `undefined` when it can. `ledger` is the connection's request
80
+ * ledger: absent when the library could not watch the transport's requests.
81
+ * A request that reaches the transport without its marker is refused there, by
82
+ * the ledger (`'request-unmatched'`).
83
+ */
84
+ function unavailableBeforeSending(ledger) {
85
+ if (ledger === undefined)
86
+ return 'requests-unwatched';
87
+ if (!ledger.answersObserved)
88
+ return 'answers-unobserved';
89
+ return undefined;
90
+ }
91
+ exports.unavailableBeforeSending = unavailableBeforeSending;
92
+ //# sourceMappingURL=replayUnavailable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replayUnavailable.js","sourceRoot":"","sources":["../../src/mcp/replayUnavailable.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;;;AAQH,yFAAyF;AACzF,MAAM,OAAO,GAAyD;IACpE,oBAAoB,EAClB,8FAA8F;IAChG,oBAAoB,EAClB,yFAAyF;QACzF,+CAA+C;IACjD,mBAAmB,EACjB,uFAAuF;QACvF,kBAAkB;CACrB,CAAC;AAEF;;;;;GAKG;AACH,MAAa,yBAA0B,SAAQ,KAAK;IAUvC;IACA;IACA;IAXF,IAAI,GAAG,4BAAqC,CAAC;IACtD;;;;OAIG;IACM,IAAI,GAAG,KAAc,CAAC;IAE/B,YACW,MAAkC,EAClC,MAAc,EACd,IAAY;QAErB,KAAK,CACH,aAAa,MAAM,mBAAmB,IAAI,8CAA8C;YACtF,0EAA0E;YAC1E,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CACxB,CAAC;QARO,WAAM,GAAN,MAAM,CAA4B;QAClC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAOrB,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AArBD,8DAqBC;AAED;;;;;;GAMG;AACH,SAAgB,wBAAwB,CACtC,MAAyD;IAEzD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,oBAAoB,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,OAAO,oBAAoB,CAAC;IACzD,OAAO,SAAS,CAAC;AACnB,CAAC;AAND,4DAMC"}