@temporalabs/treasury 0.1.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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +10 -0
  3. package/README.md +153 -0
  4. package/THIRD_PARTY_NOTICES.md +366 -0
  5. package/dist/abi/erc4626.d.ts +243 -0
  6. package/dist/abi/erc4626.js +146 -0
  7. package/dist/abi/erc4626.js.map +1 -0
  8. package/dist/build.d.ts +88 -0
  9. package/dist/build.js +124 -0
  10. package/dist/build.js.map +1 -0
  11. package/dist/client.d.ts +429 -0
  12. package/dist/client.js +248 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/config/earn.d.ts +47 -0
  15. package/dist/config/earn.js +46 -0
  16. package/dist/config/earn.js.map +1 -0
  17. package/dist/disclosures.d.ts +14 -0
  18. package/dist/disclosures.js +28 -0
  19. package/dist/disclosures.js.map +1 -0
  20. package/dist/index.d.ts +14 -0
  21. package/dist/index.js +10 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/links.d.ts +21 -0
  24. package/dist/links.js +32 -0
  25. package/dist/links.js.map +1 -0
  26. package/dist/mcp/server.d.ts +33 -0
  27. package/dist/mcp/server.js +346 -0
  28. package/dist/mcp/server.js.map +1 -0
  29. package/dist/mcp-server.mjs +56281 -0
  30. package/dist/position.d.ts +142 -0
  31. package/dist/position.js +354 -0
  32. package/dist/position.js.map +1 -0
  33. package/dist/preflight.d.ts +62 -0
  34. package/dist/preflight.js +165 -0
  35. package/dist/preflight.js.map +1 -0
  36. package/dist/quote.d.ts +55 -0
  37. package/dist/quote.js +83 -0
  38. package/dist/quote.js.map +1 -0
  39. package/dist/redact.d.ts +44 -0
  40. package/dist/redact.js +92 -0
  41. package/dist/redact.js.map +1 -0
  42. package/dist/registry-schema.d.ts +127 -0
  43. package/dist/registry-schema.js +124 -0
  44. package/dist/registry-schema.js.map +1 -0
  45. package/dist/registry.d.ts +26 -0
  46. package/dist/registry.js +62 -0
  47. package/dist/registry.js.map +1 -0
  48. package/dist/units.d.ts +8 -0
  49. package/dist/units.js +24 -0
  50. package/dist/units.js.map +1 -0
  51. package/dist/version.d.ts +1 -0
  52. package/dist/version.js +14 -0
  53. package/dist/version.js.map +1 -0
  54. package/package.json +58 -0
  55. package/registry/vaults.json +68 -0
@@ -0,0 +1,346 @@
1
+ /**
2
+ * Agent Treasury — MCP server (earn skill).
3
+ *
4
+ * Read tools, quotes, and UNSIGNED call builders only. There is no `sign` and no `send` tool, and
5
+ * there will not be one here: the skill supplies intent, the consumer supplies the signer. Anything
6
+ * that holds a key lives outside this process and receives the calls this server emits.
7
+ *
8
+ * Eight tools, all `earn_`-prefixed so later skills can sit beside them
9
+ * in one namespace:
10
+ *
11
+ * earn_vaults earn_terms earn_quote (direction) earn_status (no args = health)
12
+ * earn_balance earn_claim earn_prepare_deposit earn_prepare_withdraw
13
+ *
14
+ * Two contracts worth stating here because they are easy to erode:
15
+ *
16
+ * 1. `earn_prepare_*` return an ENVELOPE, `{ requires_signature, status: "unsigned", calls }`,
17
+ * not a bare array. This cannot stop a model reporting "deposited" — nothing at this boundary
18
+ * can — but it makes an unsigned build structurally distinguishable from a completed one, so a
19
+ * consumer or a test can assert on it. Wrapped HERE only: `buildDeposit`/`buildWithdraw` still
20
+ * return arrays, so a direct library consumer (see docs/runbooks/sign_and_send.md) gets the
21
+ * naked calls exactly as before.
22
+ * 2. The address argument is `account` everywhere. It was `depositor`, `owner` and `principal` in
23
+ * three different tools. `receiver` stays distinct because it genuinely is: `account` owns the
24
+ * shares, `receiver` is where the money lands.
25
+ */
26
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
28
+ import { z } from "zod";
29
+ import { redactEndpoints, registerSecretSource } from "../redact.js";
30
+ import { isAddress, getAddress } from "viem";
31
+ import { isSupportedChainId, makePublicClient, rpcUrlFromEnv, logsRpcUrlFromEnv, rpcSourceForEnv, resolvedRpcSecrets, publicRpcHint, logsFallbackUrlFromEnv } from "../client.js";
32
+ import { defaultVault, depositableVaults, listVaults, loadRegistry, resolveVault } from "../registry.js";
33
+ import { linksFor } from "../links.js";
34
+ import { PACKAGE_VERSION } from "../version.js";
35
+ import { preflightDeposit } from "../preflight.js";
36
+ import { getPosition } from "../position.js";
37
+ import { quoteDeposit, quoteWithdraw } from "../quote.js";
38
+ import { buildDeposit, buildWithdraw } from "../build.js";
39
+ import { DISCLOSURES } from "../disclosures.js";
40
+ const addressArg = z
41
+ .string()
42
+ .refine((s) => isAddress(s), "must be an EVM address")
43
+ .transform((s) => getAddress(s));
44
+ const amountArg = z.string().regex(/^\d+(\.\d+)?$/, 'plain decimal USDC amount, e.g. "25" or "12.5"');
45
+ const vaultArg = z.string().optional().describe("the vault's ERC-20 ticker, e.g. tlCashPlusUSDC2 (earn_vaults lists them); omit for the default vault");
46
+ const accountArg = addressArg.describe("the account whose shares these are — the depositor, the owner, the holder");
47
+ function supportedVault(symbol) {
48
+ const vault = resolveVault(symbol);
49
+ if (!isSupportedChainId(vault.chainId))
50
+ throw new Error(`chain ${vault.chainId} unsupported`);
51
+ return vault;
52
+ }
53
+ function clientFor(symbol) {
54
+ const vault = supportedVault(symbol);
55
+ return { vault, client: makePublicClient(vault.chainId, rpcUrlFromEnv(vault.chainId)) };
56
+ }
57
+ /** Shapes that mean "the transport failed", as opposed to a verdict about the vault. */
58
+ const RPC_FAILURE = /RPC Request failed|HTTP request failed|reads failed|over rate limit|rate.?limit|"unreachable"|fetch failed|ETIMEDOUT|ECONNREFUSED/i;
59
+ /**
60
+ * Serialise a tool result, and when the payload shows a TRANSPORT failure while no RPC is
61
+ * configured, attach the one sentence that turns "this is broken" into "set this variable".
62
+ * Attached as a FIELD rather than appended to prose, so a consumer can branch on it.
63
+ */
64
+ const text = (v) => {
65
+ let body = typeof v === "string" ? v : JSON.stringify(v, null, 2);
66
+ if (RPC_FAILURE.test(body)) {
67
+ const hint = publicRpcHint(8453);
68
+ if (hint) {
69
+ body =
70
+ typeof v === "string"
71
+ ? `${body}\n\n${hint}`
72
+ : JSON.stringify({ ...v, setup_required: hint }, null, 2);
73
+ }
74
+ }
75
+ return { content: [{ type: "text", text: body }] };
76
+ };
77
+ /** An unsigned build never leaves this server as a bare array. See contract 1 in the file header. */
78
+ /**
79
+ * 🔴 THE ONE PLACE THE VAULT'S WARNING IS ATTACHED TO A RESPONSE. Every response that can be the
80
+ * last thing an agent reads before a signer sees calldata goes through here.
81
+ *
82
+ * It exists as a chokepoint rather than three tidy literals for a reason worth keeping. The warning
83
+ * first shipped on `earn_vaults` alone — a DISCOVERY call — while the warning's own text says to
84
+ * show it before preparing a deposit. A caller who names a vault directly never makes that call, so
85
+ * the disclosure reached whoever happened to have listed recently and nobody else. The repair added
86
+ * it to three call sites, and two of those three were then unguarded: deleting the field from them
87
+ * left the whole suite green.
88
+ *
89
+ * A test per call site would only have guarded the sites someone remembered to write a test for,
90
+ * which is the same defect one level up. So: attach it HERE, and `server.unit.test.ts` asserts this
91
+ * is the only place in the file that writes a `warning` field. A fourth money-committing tool then
92
+ * gets the disclosure by going through this helper, and a hand-rolled one is caught by that test
93
+ * rather than by someone noticing.
94
+ *
95
+ * Withdrawals deliberately do NOT call this. The warning is about COMMITTING money, not retrieving
96
+ * it, and a disclosure repeated where it does not apply is what teaches a reader to skip the one
97
+ * that does. That absence is asserted too.
98
+ */
99
+ const commitsMoney = (vault) => ({ warning: vault.warning });
100
+ const unsigned = (calls, vault) => text({
101
+ requires_signature: true,
102
+ status: "unsigned",
103
+ // before `next_step`, so it is not past the field a reader stops at
104
+ ...(vault === undefined ? {} : commitsMoney(vault)),
105
+ next_step: "Hand these calls to a signer IN ORDER, following `signer_rules`. A call carrying `precondition` must not be estimated or sent until that read holds on the RPC the signer sends through. Nothing has been submitted; no funds have moved.",
106
+ signer_rules: SIGNER_RULES,
107
+ calls,
108
+ });
109
+ /**
110
+ * What a signer must do for these calls to land exactly once. Each rule is a failure measured on a
111
+ * real Base round trip, not a precaution (2026-09-13, two runs through these tools).
112
+ * The server cannot enforce any of them — it never signs — so it states them with every build.
113
+ */
114
+ export const SIGNER_RULES = [
115
+ "Before signing, check every call's destination against the addresses the operator gave: `to`, and the receiver/owner named in `description`. Do not sign a call whose destination you did not confirm.",
116
+ "Set the nonce explicitly from eth_getTransactionCount(account, \"pending\") immediately before each send. A load-balanced RPC can hand a signing library a stale nonce, and the send is then rejected as \"nonce too low\" (measured 2026-09-14, mainnet.base.org).",
117
+ "Set the gas limit to the call's gasAdvice (estimate × 1.5).",
118
+ "Wait for each receipt before sending the next call, and poll for it on a provider that serves receipts: a public endpoint may refuse eth_getTransactionReceipt (measured 2026-09-14, publicnode). A failed receipt poll does not mean the transaction failed.",
119
+ "If a send or receipt poll fails for any reason other than an on-chain revert, read the account's nonce on a DIFFERENT provider before re-sending. A nonce that moved means the transaction was accepted; re-sending it would repeat the deposit or withdrawal.",
120
+ ];
121
+ /**
122
+ * Every handler runs inside this. The MCP SDK forwards a thrown error's `.message` to the caller
123
+ * verbatim, and viem's messages carry the transport URL — a keyed provider URL is a secret.
124
+ * Anything that escapes a handler is re-thrown with endpoints masked.
125
+ */
126
+ const guarded = (fn) => async (...a) => {
127
+ try {
128
+ return await fn(...a);
129
+ }
130
+ catch (e) {
131
+ const msg = e instanceof Error ? e.message : String(e);
132
+ const redacted = redactEndpoints(msg);
133
+ // A thrown transport error on the public endpoint gets the same sentence a returned one does.
134
+ const hint = RPC_FAILURE.test(redacted) ? publicRpcHint(8453) : undefined;
135
+ throw new Error(hint ? `${redacted}\n\n${hint}` : redacted);
136
+ }
137
+ };
138
+ export function buildServer() {
139
+ // 🔴 Value-based redaction, registered before any handler can run. `redactEndpoints` masks the
140
+ // resolved RPC URL and its credential-bearing parts wherever they appear — including inside a
141
+ // provider's own error body, which is prose in JSON and which no shape rule matches
142
+ // (review, reproduced against a real viem client and a real 401).
143
+ registerSecretSource(resolvedRpcSecrets);
144
+ const server = new McpServer({ name: "treasury", version: PACKAGE_VERSION });
145
+ server.registerTool("earn_vaults", {
146
+ title: "List vaults",
147
+ description: "Every vault in the registry. `symbol` is the vault's own on-chain ERC-20 ticker — the value every other tool takes as `vault` — and `name` its `name()`; `links` are openable without any RPC endpoint, so an operator can verify the contract independently. SHOW `warning` TO THE DEPOSITOR — every vault offered today is a test vault. Each row also carries its backend, chassis, decimals and MEASURED deposit-open status. `default` is used when a tool is called without `vault`; `depositable` is the subset any account can put money into today: ERC-4626 chassis + measured open. `defaultAccess` says whether the default takes deposits from any account (`open`) or only whitelisted ones (`whitelist`); for `whitelist`, run earn_status for the account before preparing a deposit.",
148
+ inputSchema: {},
149
+ }, guarded(async () => {
150
+ const reg = loadRegistry();
151
+ return text({
152
+ reconciledAtIso: reg.reconciledAtIso,
153
+ default: defaultVault().symbol,
154
+ defaultAccess: defaultVault().depositOpen.open ? "open" : "whitelist",
155
+ depositable: depositableVaults().map((v) => v.symbol),
156
+ vaults: listVaults().map((v) => ({
157
+ symbol: v.symbol,
158
+ name: v.name,
159
+ warning: v.warning,
160
+ links: linksFor(v),
161
+ backend: v.backend,
162
+ isDefault: v.isDefault,
163
+ chainId: v.chainId,
164
+ address: v.address,
165
+ chassis: v.chassis,
166
+ asset: v.asset,
167
+ shareDecimals: v.shareDecimals,
168
+ depositOpen: v.depositOpen,
169
+ notes: v.notes,
170
+ })),
171
+ });
172
+ }));
173
+ server.registerTool("earn_terms", {
174
+ title: "Pre-deposit disclosures",
175
+ description: "The disclosures every distribution surface must present before a depositor's first deposit. Show these to the operator and record acknowledgement before building any deposit.",
176
+ inputSchema: {},
177
+ }, guarded(async () => text(DISCLOSURES)));
178
+ server.registerTool("earn_status", {
179
+ title: "Server health, or a deposit pre-flight verdict",
180
+ description: "With NO arguments: is the server up and the RPC reachable — chain id, latest block, registry version, and which env var supplied the RPC (never the URL). With `account`: simulates deposit() from that address and reports OPEN_READY, NEEDS_APPROVAL, WHITELIST_GATED, REVERTED_OTHER, REFUSED_BY_CLIENT or UNRESOLVED, never trusting maxDeposit(). The `mode` field says which answer you got.",
181
+ inputSchema: { vault: vaultArg, account: accountArg.optional(), amount_usdc: amountArg.optional() },
182
+ }, guarded(async ({ vault: symbol, account, amount_usdc }) => {
183
+ if (account !== undefined) {
184
+ const { vault, client } = clientFor(symbol);
185
+ const args = amount_usdc === undefined ? { vault, depositor: account, client } : { vault, depositor: account, client, assetsHuman: amount_usdc };
186
+ const verdict = await preflightDeposit(args);
187
+ // spread FIRST so the discriminant cannot be overwritten by a field of the same name
188
+ return text({ ...verdict, mode: "preflight", account, ...commitsMoney(vault) });
189
+ }
190
+ // Health. A partial call (a vault but no account) is answered here too, and says so in
191
+ // STRUCTURE rather than in prose — a note is exactly what a consumer skips, and the risk is
192
+ // a loud health result being read as a preflight pass.
193
+ //
194
+ // A schema error would also close this. It is not taken because a structural carrier is more
195
+ // forgiving to an exploring agent: `earn_status` stays answerable in every state, including
196
+ // a malformed call. This is NOT rejected on the must-never-throw rule below — that rule governs
197
+ // a RUNTIME failure on the health path (a dead RPC must yield a verdict, not an exception),
198
+ // whereas a partial-args call is an INPUT problem settled by MCP's own invalid-params layer
199
+ // before the handler body runs. The two are different layers, and conflating them would license
200
+ // "never validate inputs on a path that must not throw", which is not the rule.
201
+ //
202
+ // Only the account-missing case is "partial": `vault` HAS a default (documented as "omit for
203
+ // the default vault" across the whole tool surface), `account` has none. So {account, no vault}
204
+ // is a complete preflight against the default, not a partial call.
205
+ const partial = symbol !== undefined ? { requested: "preflight", missing: ["account"] } : {};
206
+ const vault = supportedVault(symbol);
207
+ const src = rpcSourceForEnv(vault.chainId);
208
+ const base = {
209
+ mode: "health",
210
+ ...partial,
211
+ server: "treasury",
212
+ version: PACKAGE_VERSION,
213
+ registry: { schemaVersion: loadRegistry().schemaVersion, vaults: loadRegistry().vaults.length, reconciledAtIso: loadRegistry().reconciledAtIso },
214
+ chainId: vault.chainId,
215
+ rpcSource: src.source,
216
+ rpcConfigured: src.configured,
217
+ };
218
+ // 🔴 The health path RETURNS a verdict when the RPC is unreachable. It must never throw: a
219
+ // tool that throws on a dead RPC answers nothing, which is the whole point of having it.
220
+ try {
221
+ const client = makePublicClient(vault.chainId, rpcUrlFromEnv(vault.chainId));
222
+ return text({ ...base, rpc: "ok", latestBlock: (await client.getBlockNumber()).toString() });
223
+ }
224
+ catch (e) {
225
+ const reason = redactEndpoints(e instanceof Error ? e.message : String(e));
226
+ return text({ ...base, rpc: "unreachable", latestBlock: null, reason });
227
+ }
228
+ }));
229
+ server.registerTool("earn_quote", {
230
+ title: "Quote a deposit or a withdrawal",
231
+ description: "Pre-trade quote, in USDC. direction=deposit: expected shares (previewDeposit), share price, and the access verdict from a simulated deposit(). This client quotes no rate: an ERC-4626 vault exposes none, and it calls no yield API. direction=withdraw: shares burned (previewWithdraw), shares held, a simulated withdraw() verdict, maxWithdraw advisory only (Morpho V2 returns 0 by design), and queue depth. Run before the matching earn_prepare_* tool.",
232
+ inputSchema: {
233
+ vault: vaultArg,
234
+ account: accountArg,
235
+ amount_usdc: amountArg,
236
+ direction: z.enum(["deposit", "withdraw"]).describe("which side to quote — required, there is no default"),
237
+ },
238
+ }, guarded(async ({ vault: symbol, account, amount_usdc, direction }) => {
239
+ const { vault, client } = clientFor(symbol);
240
+ // 🔴 The tag is emitted from INSIDE each branch, beside the fields that branch produces —
241
+ // never `{ direction, ...quote }` from the input argument. Measured in review: with the tag
242
+ // taken from the input, swapping these two branches left `tsc -b` clean and all 61 tests
243
+ // passing, and the result read `{ direction: "deposit", sharesToBurn: … }` — the tag said
244
+ // deposit while the body was a withdrawal. A guard derived from the wrong side of the thing
245
+ // it guards cannot detect the bug it exists for. Emitted here, tag and body are consistent
246
+ // BY CONSTRUCTION; a swapped route is then wrong about the REQUEST, which the handler test
247
+ // catches by asserting requested === returned, and never lying about the BODY.
248
+ if (direction === "deposit") {
249
+ return text({
250
+ direction: "deposit",
251
+ ...commitsMoney(vault),
252
+ ...(await quoteDeposit({ vault, depositor: account, assetsHuman: amount_usdc, client })),
253
+ });
254
+ }
255
+ return text({ direction: "withdraw", ...(await quoteWithdraw({ vault, owner: account, assetsHuman: amount_usdc, client })) });
256
+ }));
257
+ server.registerTool("earn_prepare_deposit", {
258
+ title: "Prepare an unsigned deposit",
259
+ description: "Returns the UNSIGNED calls for a deposit — [approve(asset → vault), deposit(assets, receiver)] — inside an envelope with requires_signature: true. Amount is USDC. NOTHING IS SUBMITTED: hand the calls to a signer in order. This tool cannot sign or send, and the deposit has not happened until the signer's transactions confirm. Each call also carries `function` and `args` — the same call `data` encodes, decoded, e.g. `approve(address spender, uint256 value)` with `{ spender, value }` — so an operator without a CLI signer can fill a block explorer's Write Contract form directly. `args` values are RAW contract units, which is what the form takes; `description` is the human sentence.",
260
+ inputSchema: {
261
+ vault: vaultArg,
262
+ account: accountArg.describe("the depositing account — the one that signs both calls; step 2's allowance precondition is read for it"),
263
+ amount_usdc: amountArg,
264
+ receiver: addressArg.describe("where the SHARES land — usually the account, not necessarily"),
265
+ },
266
+ }, guarded(async ({ vault: symbol, account, amount_usdc, receiver }) => {
267
+ const vault = supportedVault(symbol);
268
+ return unsigned(buildDeposit(vault, { assetsHuman: amount_usdc, receiver, account }), vault);
269
+ }));
270
+ server.registerTool("earn_prepare_withdraw", {
271
+ title: "Prepare an unsigned withdrawal",
272
+ description: "Returns the UNSIGNED call for a withdrawal in USDC terms — withdraw(assets, receiver, owner) — inside an envelope with requires_signature: true. To empty the account pass all=true with shares_exact copied verbatim from earn_balance.sharesExact (redeem of the exact balance; never a rounded number). NOTHING IS SUBMITTED and no funds have moved until a signer confirms. Each call also carries `function` and `args` — the same call `data` encodes, decoded, e.g. `approve(address spender, uint256 value)` with `{ spender, value }` — so an operator without a CLI signer can fill a block explorer's Write Contract form directly. `args` values are RAW contract units, which is what the form takes; `description` is the human sentence.",
273
+ inputSchema: {
274
+ vault: vaultArg,
275
+ receiver: addressArg.describe("where the USDC lands — NOT necessarily the account"),
276
+ account: accountArg.describe("whose shares are burnt"),
277
+ amount_usdc: amountArg.optional(),
278
+ all: z.boolean().optional(),
279
+ shares_exact: z.string().regex(/^\d+(\.\d+)?$/).optional(),
280
+ },
281
+ }, guarded(async ({ vault: symbol, receiver, account, amount_usdc, all, shares_exact }) => {
282
+ const vault = supportedVault(symbol);
283
+ // ⚠️ `receiver` and `account` are DIFFERENT slots and both are addresses, so a transposition
284
+ // here type-checks. `account` is the owner whose shares burn; `receiver` is the payee.
285
+ if (all) {
286
+ if (!shares_exact)
287
+ throw new Error("all=true requires shares_exact (copy earn_balance.sharesExact verbatim)");
288
+ return unsigned(buildWithdraw(vault, { receiver, owner: account, all: true, sharesExact: shares_exact }));
289
+ }
290
+ if (!amount_usdc)
291
+ throw new Error("provide amount_usdc, or all=true with shares_exact");
292
+ return unsigned(buildWithdraw(vault, { receiver, owner: account, assetsHuman: amount_usdc }));
293
+ }));
294
+ server.registerTool("earn_balance", {
295
+ title: "Earn position",
296
+ description: "Shares held (exact string + display), current USDC value, WHAT CAN ACTUALLY BE WITHDRAWN NOW (`exit`, measured by simulating the withdrawal — `usdcValue` is what the position is worth, `exit.exitableNow` is what the vault can pay; on a Fusion vault without instant-withdrawal fuses they differ by 10x and `maxWithdraw()` reports the larger one), entry basis and accrued yield derived from the vault's own Deposit/Withdraw events for this account, and share price. `scan.complete` says whether the event window covered the whole position; `sharesExact` is what earn_prepare_withdraw({ all }) needs. `scan.depositTxs` and `scan.withdrawTxs` carry the transactions behind those events — `{ txHash, blockNumber, amountUsdc }`, oldest first — so an operator can be shown an explorer link without anyone rebuilding the log query; each list holds at most the 100 most recent, while `scan.deposits`/`scan.withdrawals` stay the totals.",
297
+ inputSchema: {
298
+ vault: vaultArg,
299
+ account: accountArg,
300
+ lookback_blocks: z.number().int().positive().optional().describe("how far back to scan for Deposit/Withdraw events; default: from the vault's deployment block, i.e. the whole history. The EFFECTIVE window is max_log_requests × the provider's eth_getLogs cap (Alchemy free 10 blocks, Base public 2,000); if the configured RPC cannot cover it, Base's public endpoint serves the scan and scan.source says so"),
301
+ max_log_requests: z.number().int().positive().max(400).optional().describe("cap on eth_getLogs calls per event per scan; default 100 (= 1,000 blocks on Alchemy free, 200,000 on Base public). scan.wholeHistory says whether the scan actually covered every block since the vault was deployed — scan.complete alone is only a reconciliation and can be vacuously true. For an older vault, a provider with a wide eth_getLogs range (TREASURY_LOGS_RPC_BASE) is what makes it whole"),
302
+ },
303
+ }, guarded(async ({ vault: symbol, account, lookback_blocks, max_log_requests }) => {
304
+ const vault = supportedVault(symbol);
305
+ const logsUrl = logsRpcUrlFromEnv(vault.chainId);
306
+ const client = makePublicClient(vault.chainId, logsUrl);
307
+ // `logsFallbackUrlFromEnv` returns undefined when the operator opted out or when the fallback
308
+ // would be the primary itself — the wiring is a one-liner precisely so it can be unit-tested
309
+ // (measured in review: mutating this line to `undefined` left every position-layer test green;
310
+ // `server.unit.test.ts` is what fails now).
311
+ const fallbackUrl = logsFallbackUrlFromEnv(vault.chainId, logsUrl);
312
+ const fallbackClient = fallbackUrl === undefined ? undefined : makePublicClient(vault.chainId, fallbackUrl);
313
+ return text(await getPosition({
314
+ vault,
315
+ principal: account,
316
+ client,
317
+ ...(fallbackClient ? { fallbackClient } : {}),
318
+ ...(lookback_blocks === undefined ? {} : { lookbackBlocks: BigInt(lookback_blocks) }),
319
+ ...(max_log_requests === undefined ? {} : { maxLogRequests: max_log_requests }),
320
+ }));
321
+ }));
322
+ server.registerTool("earn_claim", {
323
+ title: "Claim a queued withdrawal",
324
+ description: "Finalizes a queued withdrawal on chassis that settle asynchronously. No vault in the current registry queues — Morpho V2 and Fusion settle in the withdraw transaction — so this reports that nothing is claimable. Present so callers can code against the full contract before an async chassis (e.g. a queued-redemption fund) is added.",
325
+ inputSchema: { receipt_id: z.string() },
326
+ }, guarded(async ({ receipt_id }) => text({
327
+ receipt_id,
328
+ status: "nothing_to_claim",
329
+ note: "No chassis in the registry queues withdrawals; a withdraw() that succeeded already delivered the USDC. When an async chassis is added, this tool will finalize its claim handle.",
330
+ })));
331
+ return server;
332
+ }
333
+ async function main() {
334
+ const server = buildServer();
335
+ await server.connect(new StdioServerTransport());
336
+ }
337
+ if (process.argv[1] && /server\.(ts|mjs|js)$/.test(process.argv[1])) {
338
+ main().catch((e) => {
339
+ // Defence-in-depth: HARDENED, NOT TESTED. main() only builds the server and connects a stdio
340
+ // transport — every RPC URL is resolved inside a handler body, so nothing reachable here can
341
+ // carry one. This guard exists so that stays true if main() ever grows.
342
+ process.stderr.write(`treasury mcp: ${redactEndpoints(String(e))}\n`);
343
+ process.exit(1);
344
+ });
345
+ }
346
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}