@temporalabs/treasury 0.1.1 → 0.1.2

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 (74) hide show
  1. package/NOTICE +4 -2
  2. package/README.md +68 -44
  3. package/THIRD_PARTY_NOTICES.connect-page.md +7420 -0
  4. package/THIRD_PARTY_NOTICES.md +4 -196
  5. package/dist/cli.d.ts +6 -0
  6. package/dist/cli.js +220 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/client.d.ts +224 -239
  9. package/dist/client.js +147 -25
  10. package/dist/client.js.map +1 -1
  11. package/dist/config/earn.d.ts +33 -12
  12. package/dist/config/earn.js +33 -12
  13. package/dist/config/earn.js.map +1 -1
  14. package/dist/connect/ack.d.ts +59 -0
  15. package/dist/connect/ack.js +111 -0
  16. package/dist/connect/ack.js.map +1 -0
  17. package/dist/connect/commands.d.ts +78 -0
  18. package/dist/connect/commands.js +411 -0
  19. package/dist/connect/commands.js.map +1 -0
  20. package/dist/connect/config.d.ts +22 -0
  21. package/dist/connect/config.js +33 -0
  22. package/dist/connect/config.js.map +1 -0
  23. package/dist/connect/gate.d.ts +37 -0
  24. package/dist/connect/gate.js +115 -0
  25. package/dist/connect/gate.js.map +1 -0
  26. package/dist/connect/http.d.ts +54 -0
  27. package/dist/connect/http.js +205 -0
  28. package/dist/connect/http.js.map +1 -0
  29. package/dist/connect/open.d.ts +2 -0
  30. package/dist/connect/open.js +35 -0
  31. package/dist/connect/open.js.map +1 -0
  32. package/dist/connect/page.d.ts +5 -0
  33. package/dist/connect/page.js +69 -0
  34. package/dist/connect/page.js.map +1 -0
  35. package/dist/connect/session.d.ts +16 -0
  36. package/dist/connect/session.js +73 -0
  37. package/dist/connect/session.js.map +1 -0
  38. package/dist/connect/verify.d.ts +37 -0
  39. package/dist/connect/verify.js +89 -0
  40. package/dist/connect/verify.js.map +1 -0
  41. package/dist/connect-page.js +5141 -0
  42. package/dist/disclosures.d.ts +21 -6
  43. package/dist/disclosures.js +32 -7
  44. package/dist/disclosures.js.map +1 -1
  45. package/dist/earn/commands.d.ts +46 -0
  46. package/dist/earn/commands.js +483 -0
  47. package/dist/earn/commands.js.map +1 -0
  48. package/dist/links.d.ts +2 -0
  49. package/dist/links.js +38 -14
  50. package/dist/links.js.map +1 -1
  51. package/dist/position.d.ts +7 -5
  52. package/dist/position.js +35 -18
  53. package/dist/position.js.map +1 -1
  54. package/dist/preflight.d.ts +9 -0
  55. package/dist/preflight.js +14 -3
  56. package/dist/preflight.js.map +1 -1
  57. package/dist/quote.js +24 -7
  58. package/dist/quote.js.map +1 -1
  59. package/dist/redact.d.ts +3 -3
  60. package/dist/redact.js +3 -3
  61. package/dist/redact.js.map +1 -1
  62. package/dist/registry-schema.d.ts +5 -5
  63. package/dist/registry-schema.js +30 -16
  64. package/dist/registry-schema.js.map +1 -1
  65. package/dist/registry.d.ts +29 -6
  66. package/dist/registry.js +76 -13
  67. package/dist/registry.js.map +1 -1
  68. package/dist/{mcp-server.mjs → treasury.mjs} +29276 -44702
  69. package/dist/version.js +1 -1
  70. package/package.json +5 -5
  71. package/registry/vaults.json +105 -4
  72. package/dist/mcp/server.d.ts +0 -8
  73. package/dist/mcp/server.js +0 -368
  74. package/dist/mcp/server.js.map +0 -1
package/dist/version.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * Same resolution trick as registry.ts: this file sits at src/ top level and the bundle at dist/
8
8
  * top level, so `../package.json` is the package manifest at the repository root from both.
9
9
  * Resolved from this file's REAL path: under `--preserve-symlinks-main`, `import.meta.url` is the
10
- * path of a symlink to the bundle (npm's `.bin/treasury-mcp`), and `../package.json` from there is a
10
+ * path of a symlink to the bundle (npm's `.bin/treasury`), and `../package.json` from there is a
11
11
  * file in whatever directory holds the link.
12
12
  */
13
13
  import { readFileSync, realpathSync } from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporalabs/treasury",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,6 +10,7 @@
10
10
  "LICENSE",
11
11
  "NOTICE",
12
12
  "THIRD_PARTY_NOTICES.md",
13
+ "THIRD_PARTY_NOTICES.connect-page.md",
13
14
  "dist",
14
15
  "registry"
15
16
  ],
@@ -22,7 +23,7 @@
22
23
  "main": "./dist/index.js",
23
24
  "types": "./dist/index.d.ts",
24
25
  "bin": {
25
- "treasury-mcp": "./dist/mcp-server.mjs"
26
+ "treasury": "./dist/treasury.mjs"
26
27
  },
27
28
  "exports": {
28
29
  ".": {
@@ -34,19 +35,18 @@
34
35
  "node": ">=22"
35
36
  },
36
37
  "scripts": {
37
- "prepack": "npm run build && git diff --exit-code -- dist/mcp-server.mjs THIRD_PARTY_NOTICES.md",
38
+ "prepack": "npm run build && git diff --exit-code -- dist/treasury.mjs THIRD_PARTY_NOTICES.md",
38
39
  "build": "tsc -b && tsup && tsx scripts/third-party-notices.ts --write && bash scripts/sync-plugin.sh",
39
40
  "typecheck": "tsc -b && tsc -p tsconfig.scripts.json",
40
41
  "test": "tsc -b && tsc -p tsconfig.scripts.json && vitest run",
41
42
  "test:fork": "tsc -b && TREASURY_FORK=1 vitest run --testTimeout 300000 tests/fork.test.ts",
42
- "mcp": "tsx src/mcp/server.ts",
43
+ "cli": "tsx src/cli.ts",
43
44
  "registry:check": "tsx scripts/registry-check.ts",
44
45
  "notices:check": "tsx scripts/third-party-notices.ts",
45
46
  "plugin:check": "bash scripts/sync-plugin.sh --check && bash scripts/check-versions.sh",
46
47
  "lint:skill": "bash scripts/lint-skill.sh"
47
48
  },
48
49
  "dependencies": {
49
- "@modelcontextprotocol/sdk": "^1.20.0",
50
50
  "viem": "^2.37.0",
51
51
  "zod": "^4.1.0"
52
52
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "reconciledAtIso": "2026-09-18T16:25:46Z",
3
+ "reconciledAtIso": "2026-10-04T21:22:04Z",
4
4
  "vaults": [
5
5
  {
6
6
  "symbol": "tlCashPlusUSDC2",
@@ -10,7 +10,7 @@
10
10
  "address": "0x040fCA12673778FEED5DA7b2ccFbbAb0cc0134Cf",
11
11
  "chassis": "morpho-v2",
12
12
  "backend": "tempora",
13
- "isDefault": true,
13
+ "isDefault": false,
14
14
  "asset": {
15
15
  "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
16
16
  "symbol": "USDC",
@@ -30,7 +30,7 @@
30
30
  "Morpho Vault V2. maxDeposit() and maxWithdraw() return 0 to every caller by protocol design; the pre-flight simulates the real call and earn_balance simulates the exit. Neither reads those views.",
31
31
  "Withdrawals are served from idle USDC, then through the vault's liquidity adapter; a withdrawal larger than that reverts until positions are unwound. earn_balance reports exitableNow by simulating the withdrawal.",
32
32
  "No fee is set: performanceFee() = 0 and managementFee() = 0 at block 51372415. The curator can introduce one, and the vault's fee timelocks are 0 (timelock(setPerformanceFee) = timelock(setManagementFee) = 0 at block 51404161), so a change needs no notice. Read both fees before depositing.",
33
- "The DEFAULT vault, and open to any account: it is in depositable."
33
+ "The DEMO vault. Open to any account and in depositable, but not the default: name it with `--vault tlCashPlusUSDC2`. Its structure is the one Test 2B restores as a sibling."
34
34
  ]
35
35
  },
36
36
  {
@@ -60,9 +60,110 @@
60
60
  "notes": [
61
61
  "8-decimal shares against a 6-decimal asset — a share amount is never an asset amount here.",
62
62
  "getInstantWithdrawalFuses() returns three fuses (measured at block 51361109), so a withdrawal is served from the vault's liquid balance and then, in fuse order, by unwinding its positions in the same transaction. A withdrawal larger than what those positions can release in-block still reverts; earn_balance reports exitableNow, which simulates the withdrawal rather than reading maxWithdraw.",
63
- "Deposits need role 800 on the AccessManager. An account without it gets WHITELIST_GATED from earn_status and earn_quote, and this client refuses to build a deposit for it. Withdrawals are public.",
63
+ "Deposits need role 800 on the AccessManager. An account without it gets WHITELIST_GATED from earn_status and earn_quote. Neither earn prepare_deposit nor connect deposit checks the role: a deposit built for such an account reverts on-chain (AccessManagedUnauthorized), so run earn_status for the account first. Withdrawals are public.",
64
64
  "Whitelist-gated (role 800 on its AccessManager): not in depositable. Listed so that an admitted account's position can be read and exited; a non-member gets WHITELIST_GATED from earn_status before anything is built."
65
65
  ]
66
+ },
67
+ {
68
+ "symbol": "tlCashPlusUSDC2B",
69
+ "name": "Tempora Labs Cash Plus USDC (Test 2B)",
70
+ "warning": "TEST VAULT — unproven. It exists to exercise this product, not to hold savings. Deposit only an amount you are fully prepared to lose entirely, and do not move significant funds into it. Show this warning before preparing any deposit.",
71
+ "chainId": 8453,
72
+ "address": "0x91BcEbA5feCB9E92d80F1845B55cC56621E9352F",
73
+ "chassis": "morpho-v2",
74
+ "backend": "tempora",
75
+ "isDefault": true,
76
+ "asset": {
77
+ "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
78
+ "symbol": "USDC",
79
+ "decimals": 6
80
+ },
81
+ "shareDecimals": 18,
82
+ "depositOpen": {
83
+ "open": true,
84
+ "method": "simulated-deposit-from-stranger",
85
+ "measuredAtBlock": 52097648,
86
+ "measuredAtIso": "2026-10-02T23:44:03Z",
87
+ "detail": "deposit(1 USDC, 0x…dEaD) from 0x…dEaD reverted 0xe65b7a77 TransferFromReverted at block 52097648 — it reached the token pull, so access is open; maxDeposit() reads 0 to every caller on this chassis by design and is not consulted."
88
+ },
89
+ "deployedAtBlock": 51436870,
90
+ "notes": [
91
+ "18-decimal shares against a 6-decimal asset — a share amount is never an asset amount here.",
92
+ "Morpho Vault V2. maxDeposit() and maxWithdraw() return 0 to every caller by protocol design; the pre-flight simulates the real call and earn_balance simulates the exit. Neither reads those views.",
93
+ "Withdrawals are served from idle USDC, then through the vault's liquidity adapter; a withdrawal larger than that reverts until positions are unwound. earn_balance reports exitableNow by simulating the withdrawal.",
94
+ "No fee is set: performanceFee() = 0 and managementFee() = 0 at block 52097648. The curator can introduce one, and the vault's fee timelocks are 0 (timelock(setPerformanceFee) = timelock(setManagementFee) = 0 at block 52097648), so a change needs no notice. Read both fees before depositing.",
95
+ "Three configured adapters (measured at block 52097648); Treasury does not model the fund's allocation across them — read the vault's positions on-chain before a first deposit.",
96
+ "Morpho's own app has no page for this vault (app.morpho.org answered 404 for it on 2026-10-02, and Morpho's API does not list it), unlike Test 2. Positions cannot be cross-checked there; verify on-chain or on BaseScan instead.",
97
+ "The DEFAULT vault on Base, and open to any account: it is in depositable."
98
+ ]
99
+ },
100
+ {
101
+ "symbol": "tlCashPlusUSDC2C",
102
+ "name": "Tempora Labs Cash Plus USDC (Test 2C)",
103
+ "warning": "TEST VAULT — unproven. It exists to exercise this product, not to hold savings. Deposit only an amount you are fully prepared to lose entirely, and do not move significant funds into it. Show this warning before preparing any deposit.",
104
+ "chainId": 42161,
105
+ "address": "0x4057a63953142Ac2b3E5dB1954Fc14d578662587",
106
+ "chassis": "morpho-v2",
107
+ "backend": "tempora",
108
+ "isDefault": true,
109
+ "asset": {
110
+ "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
111
+ "symbol": "USDC",
112
+ "decimals": 6
113
+ },
114
+ "shareDecimals": 18,
115
+ "depositOpen": {
116
+ "open": true,
117
+ "method": "simulated-deposit-from-stranger",
118
+ "measuredAtBlock": 511070816,
119
+ "measuredAtIso": "2026-10-02T18:43:33Z",
120
+ "detail": "deposit(1 USDC, 0x…dEaD) from 0x…dEaD reverted 0xe65b7a77 TransferFromReverted at block 511070816 — it reached the token pull, so access is open; maxDeposit() reads 0 to every caller on this chassis by design and is not consulted."
121
+ },
122
+ "deployedAtBlock": 510270114,
123
+ "notes": [
124
+ "On Arbitrum One (chain 42161). Calls for this vault are sent on Arbitrum, and its RPC is TREASURY_RPC_ARBITRUM.",
125
+ "The asset is native USDC on Arbitrum One, not bridged USDC.e, which is a different token this vault does not take.",
126
+ "18-decimal shares against a 6-decimal asset — a share amount is never an asset amount here.",
127
+ "Morpho Vault V2. maxDeposit() and maxWithdraw() return 0 to every caller by protocol design; the pre-flight simulates the real call and earn_balance simulates the exit. Neither reads those views.",
128
+ "Withdrawals are served from idle USDC, then through the vault's liquidity adapter; a withdrawal larger than that reverts until positions are unwound. earn_balance reports exitableNow by simulating the withdrawal.",
129
+ "No fee is set: performanceFee() = 0 and managementFee() = 0 at block 511070816. The curator can introduce one, and the vault's fee timelocks are 0 (timelock(setPerformanceFee) = timelock(setManagementFee) = 0 at block 511070816), so a change needs no notice. Read both fees before depositing.",
130
+ "The default vault on Arbitrum One, and open to any account: it is in depositable."
131
+ ]
132
+ },
133
+ {
134
+ "symbol": "tlCashPlusUSDG2D",
135
+ "name": "Tempora Labs Cash Plus USDG (Test 2D)",
136
+ "warning": "TEST VAULT — unproven. It exists to exercise this product, not to hold savings. Deposit only an amount you are fully prepared to lose entirely, and do not move significant funds into it. Show this warning before preparing any deposit.",
137
+ "chainId": 4663,
138
+ "address": "0x758f00731943aA88e8C7fB709e0B727903B4F833",
139
+ "chassis": "morpho-v2",
140
+ "backend": "tempora",
141
+ "isDefault": true,
142
+ "asset": {
143
+ "address": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
144
+ "symbol": "USDG",
145
+ "decimals": 6
146
+ },
147
+ "shareDecimals": 18,
148
+ "depositOpen": {
149
+ "open": true,
150
+ "method": "simulated-deposit-from-stranger",
151
+ "measuredAtBlock": 79974900,
152
+ "measuredAtIso": "2026-10-04T13:35:53Z",
153
+ "detail": "deposit(1 USDG, 0x…dEaD) from 0x…dEaD reverted 0xe65b7a77 TransferFromReverted at block 79974900 — it reached the token pull, so access is open; maxDeposit() reads 0 to every caller on this chassis by design and is not consulted."
154
+ },
155
+ "deployedAtBlock": 79381803,
156
+ "notes": [
157
+ "On Robinhood Chain (chain 4663). Calls for this vault are sent on Robinhood Chain, and its RPC is TREASURY_RPC_ROBINHOOD.",
158
+ "The asset is USDG (Global Dollar), not USDC: the first vault in this registry whose asset is not USDC. Amounts in and out of this vault are USDG, in USDG's own 6 decimals; a tool argument or result field named for USDC (amount_usdc, usdcValue) carries USDG here.",
159
+ "18-decimal shares against a 6-decimal asset — a share amount is never an asset amount here.",
160
+ "Morpho Vault V2. maxDeposit() and maxWithdraw() return 0 to every caller by protocol design; the pre-flight simulates the real call and earn_balance simulates the exit. Neither reads those views.",
161
+ "Withdrawals are served from idle USDG, then through the vault's liquidity adapter; a withdrawal larger than that reverts until positions are unwound. earn_balance reports exitableNow by simulating the withdrawal.",
162
+ "No fee is set: performanceFee() = 0 and managementFee() = 0 at block 79974900. The curator can introduce one, and the vault's fee timelocks are 0 (timelock(setPerformanceFee) = timelock(setManagementFee) = 0 at block 79974900), so a change needs no notice. Read both fees before depositing.",
163
+ "Three configured adapters (measured at block 79974900); Treasury does not model the fund's allocation across them — read the vault's positions on-chain before a first deposit.",
164
+ "The public Robinhood Chain endpoint answered a single eth_getLogs over 674,901 blocks (79,300,000 to 79,974,900, on 2026-10-04), which covers this vault's whole history; it does not serve state at past blocks, which nothing in this client reads.",
165
+ "The default vault on Robinhood Chain, and open to any account: it is in depositable."
166
+ ]
66
167
  }
67
168
  ]
68
169
  }
@@ -1,8 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- /**
3
- * What a signer must do for these calls to land exactly once. Each rule is a failure measured on a
4
- * real Base round trip, not a precaution (2026-09-13, two runs through these tools).
5
- * The server cannot enforce any of them — it never signs — so it states them with every build.
6
- */
7
- export declare const SIGNER_RULES: readonly ["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.", "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).", "Set the gas limit to the call's gasAdvice (estimate × 1.5).", "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.", "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."];
8
- export declare function buildServer(): McpServer;
@@ -1,368 +0,0 @@
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 { realpathSync } from "node:fs";
27
- import { fileURLToPath } from "node:url";
28
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
29
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
30
- import { z } from "zod";
31
- import { redactEndpoints, registerSecretSource } from "../redact.js";
32
- import { isAddress, getAddress } from "viem";
33
- import { isSupportedChainId, makePublicClient, rpcUrlFromEnv, logsRpcUrlFromEnv, rpcSourceForEnv, resolvedRpcSecrets, publicRpcHint, logsFallbackUrlFromEnv } from "../client.js";
34
- import { defaultVault, depositableVaults, listVaults, loadRegistry, resolveVault } from "../registry.js";
35
- import { linksFor } from "../links.js";
36
- import { PACKAGE_VERSION } from "../version.js";
37
- import { preflightDeposit } from "../preflight.js";
38
- import { getPosition } from "../position.js";
39
- import { quoteDeposit, quoteWithdraw } from "../quote.js";
40
- import { buildDeposit, buildWithdraw } from "../build.js";
41
- import { DISCLOSURES } from "../disclosures.js";
42
- const addressArg = z
43
- .string()
44
- .refine((s) => isAddress(s), "must be an EVM address")
45
- .transform((s) => getAddress(s));
46
- const amountArg = z.string().regex(/^\d+(\.\d+)?$/, 'plain decimal USDC amount, e.g. "25" or "12.5"');
47
- const vaultArg = z.string().optional().describe("the vault's ERC-20 ticker, e.g. tlCashPlusUSDC2 (earn_vaults lists them); omit for the default vault");
48
- const accountArg = addressArg.describe("the account whose shares these are — the depositor, the owner, the holder");
49
- function supportedVault(symbol) {
50
- const vault = resolveVault(symbol);
51
- if (!isSupportedChainId(vault.chainId))
52
- throw new Error(`chain ${vault.chainId} unsupported`);
53
- return vault;
54
- }
55
- function clientFor(symbol) {
56
- const vault = supportedVault(symbol);
57
- return { vault, client: makePublicClient(vault.chainId, rpcUrlFromEnv(vault.chainId)) };
58
- }
59
- /** Shapes that mean "the transport failed", as opposed to a verdict about the vault. */
60
- const RPC_FAILURE = /RPC Request failed|HTTP request failed|reads failed|over rate limit|rate.?limit|"unreachable"|fetch failed|ETIMEDOUT|ECONNREFUSED/i;
61
- /**
62
- * Serialise a tool result, and when the payload shows a TRANSPORT failure while no RPC is
63
- * configured, attach the one sentence that turns "this is broken" into "set this variable".
64
- * Attached as a FIELD rather than appended to prose, so a consumer can branch on it.
65
- */
66
- const text = (v) => {
67
- let body = typeof v === "string" ? v : JSON.stringify(v, null, 2);
68
- if (RPC_FAILURE.test(body)) {
69
- const hint = publicRpcHint(8453);
70
- if (hint) {
71
- body =
72
- typeof v === "string"
73
- ? `${body}\n\n${hint}`
74
- : JSON.stringify({ ...v, setup_required: hint }, null, 2);
75
- }
76
- }
77
- return { content: [{ type: "text", text: body }] };
78
- };
79
- /** An unsigned build never leaves this server as a bare array. See contract 1 in the file header. */
80
- /**
81
- * 🔴 THE ONE PLACE THE VAULT'S WARNING IS ATTACHED TO A RESPONSE. Every response that can be the
82
- * last thing an agent reads before a signer sees calldata goes through here.
83
- *
84
- * It exists as a chokepoint rather than three tidy literals for a reason worth keeping. The warning
85
- * first shipped on `earn_vaults` alone — a DISCOVERY call — while the warning's own text says to
86
- * show it before preparing a deposit. A caller who names a vault directly never makes that call, so
87
- * the disclosure reached whoever happened to have listed recently and nobody else. The repair added
88
- * it to three call sites, and two of those three were then unguarded: deleting the field from them
89
- * left the whole suite green.
90
- *
91
- * A test per call site would only have guarded the sites someone remembered to write a test for,
92
- * which is the same defect one level up. So: attach it HERE, and `server.unit.test.ts` asserts this
93
- * is the only place in the file that writes a `warning` field. A fourth money-committing tool then
94
- * gets the disclosure by going through this helper, and a hand-rolled one is caught by that test
95
- * rather than by someone noticing.
96
- *
97
- * Withdrawals deliberately do NOT call this. The warning is about COMMITTING money, not retrieving
98
- * it, and a disclosure repeated where it does not apply is what teaches a reader to skip the one
99
- * that does. That absence is asserted too.
100
- */
101
- const commitsMoney = (vault) => ({ warning: vault.warning });
102
- const unsigned = (calls, vault) => text({
103
- requires_signature: true,
104
- status: "unsigned",
105
- // before `next_step`, so it is not past the field a reader stops at
106
- ...(vault === undefined ? {} : commitsMoney(vault)),
107
- 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.",
108
- signer_rules: SIGNER_RULES,
109
- calls,
110
- });
111
- /**
112
- * What a signer must do for these calls to land exactly once. Each rule is a failure measured on a
113
- * real Base round trip, not a precaution (2026-09-13, two runs through these tools).
114
- * The server cannot enforce any of them — it never signs — so it states them with every build.
115
- */
116
- export const SIGNER_RULES = [
117
- "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.",
118
- "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).",
119
- "Set the gas limit to the call's gasAdvice (estimate × 1.5).",
120
- "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.",
121
- "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.",
122
- ];
123
- /**
124
- * Every handler runs inside this. The MCP SDK forwards a thrown error's `.message` to the caller
125
- * verbatim, and viem's messages carry the transport URL — a keyed provider URL is a secret.
126
- * Anything that escapes a handler is re-thrown with endpoints masked.
127
- */
128
- const guarded = (fn) => async (...a) => {
129
- try {
130
- return await fn(...a);
131
- }
132
- catch (e) {
133
- const msg = e instanceof Error ? e.message : String(e);
134
- const redacted = redactEndpoints(msg);
135
- // A thrown transport error on the public endpoint gets the same sentence a returned one does.
136
- const hint = RPC_FAILURE.test(redacted) ? publicRpcHint(8453) : undefined;
137
- throw new Error(hint ? `${redacted}\n\n${hint}` : redacted);
138
- }
139
- };
140
- export function buildServer() {
141
- // 🔴 Value-based redaction, registered before any handler can run. `redactEndpoints` masks the
142
- // resolved RPC URL and its credential-bearing parts wherever they appear — including inside a
143
- // provider's own error body, which is prose in JSON and which no shape rule matches
144
- // (review, reproduced against a real viem client and a real 401).
145
- registerSecretSource(resolvedRpcSecrets);
146
- const server = new McpServer({ name: "treasury", version: PACKAGE_VERSION });
147
- server.registerTool("earn_vaults", {
148
- title: "List vaults",
149
- 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.",
150
- inputSchema: {},
151
- }, guarded(async () => {
152
- const reg = loadRegistry();
153
- return text({
154
- reconciledAtIso: reg.reconciledAtIso,
155
- default: defaultVault().symbol,
156
- defaultAccess: defaultVault().depositOpen.open ? "open" : "whitelist",
157
- depositable: depositableVaults().map((v) => v.symbol),
158
- vaults: listVaults().map((v) => ({
159
- symbol: v.symbol,
160
- name: v.name,
161
- warning: v.warning,
162
- links: linksFor(v),
163
- backend: v.backend,
164
- isDefault: v.isDefault,
165
- chainId: v.chainId,
166
- address: v.address,
167
- chassis: v.chassis,
168
- asset: v.asset,
169
- shareDecimals: v.shareDecimals,
170
- depositOpen: v.depositOpen,
171
- notes: v.notes,
172
- })),
173
- });
174
- }));
175
- server.registerTool("earn_terms", {
176
- title: "Pre-deposit disclosures",
177
- 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.",
178
- inputSchema: {},
179
- }, guarded(async () => text(DISCLOSURES)));
180
- server.registerTool("earn_status", {
181
- title: "Server health, or a deposit pre-flight verdict",
182
- 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.",
183
- inputSchema: { vault: vaultArg, account: accountArg.optional(), amount_usdc: amountArg.optional() },
184
- }, guarded(async ({ vault: symbol, account, amount_usdc }) => {
185
- if (account !== undefined) {
186
- const { vault, client } = clientFor(symbol);
187
- const args = amount_usdc === undefined ? { vault, depositor: account, client } : { vault, depositor: account, client, assetsHuman: amount_usdc };
188
- const verdict = await preflightDeposit(args);
189
- // spread FIRST so the discriminant cannot be overwritten by a field of the same name
190
- return text({ ...verdict, mode: "preflight", account, ...commitsMoney(vault) });
191
- }
192
- // Health. A partial call (a vault but no account) is answered here too, and says so in
193
- // STRUCTURE rather than in prose — a note is exactly what a consumer skips, and the risk is
194
- // a loud health result being read as a preflight pass.
195
- //
196
- // A schema error would also close this. It is not taken because a structural carrier is more
197
- // forgiving to an exploring agent: `earn_status` stays answerable in every state, including
198
- // a malformed call. This is NOT rejected on the must-never-throw rule below — that rule governs
199
- // a RUNTIME failure on the health path (a dead RPC must yield a verdict, not an exception),
200
- // whereas a partial-args call is an INPUT problem settled by MCP's own invalid-params layer
201
- // before the handler body runs. The two are different layers, and conflating them would license
202
- // "never validate inputs on a path that must not throw", which is not the rule.
203
- //
204
- // Only the account-missing case is "partial": `vault` HAS a default (documented as "omit for
205
- // the default vault" across the whole tool surface), `account` has none. So {account, no vault}
206
- // is a complete preflight against the default, not a partial call.
207
- const partial = symbol !== undefined ? { requested: "preflight", missing: ["account"] } : {};
208
- const vault = supportedVault(symbol);
209
- const src = rpcSourceForEnv(vault.chainId);
210
- const base = {
211
- mode: "health",
212
- ...partial,
213
- server: "treasury",
214
- version: PACKAGE_VERSION,
215
- registry: { schemaVersion: loadRegistry().schemaVersion, vaults: loadRegistry().vaults.length, reconciledAtIso: loadRegistry().reconciledAtIso },
216
- chainId: vault.chainId,
217
- rpcSource: src.source,
218
- rpcConfigured: src.configured,
219
- };
220
- // 🔴 The health path RETURNS a verdict when the RPC is unreachable. It must never throw: a
221
- // tool that throws on a dead RPC answers nothing, which is the whole point of having it.
222
- try {
223
- const client = makePublicClient(vault.chainId, rpcUrlFromEnv(vault.chainId));
224
- return text({ ...base, rpc: "ok", latestBlock: (await client.getBlockNumber()).toString() });
225
- }
226
- catch (e) {
227
- const reason = redactEndpoints(e instanceof Error ? e.message : String(e));
228
- return text({ ...base, rpc: "unreachable", latestBlock: null, reason });
229
- }
230
- }));
231
- server.registerTool("earn_quote", {
232
- title: "Quote a deposit or a withdrawal",
233
- 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, `instantLiquidity` — the vault's own liquid balance of the asset, which is chassis-specific in BOTH directions: a Fusion vault without instant-withdrawal fuses pays only from it, so there it is the ceiling maxWithdraw() does not know; a Morpho V2 vault holds almost none and still pays out of its markets, so there it is near zero and NOT a ceiling — the simulated verdict is what decides — maxWithdraw advisory only (Morpho V2 returns 0 by design), and queue depth. Run before the matching earn_prepare_* tool.",
234
- inputSchema: {
235
- vault: vaultArg,
236
- account: accountArg,
237
- amount_usdc: amountArg,
238
- direction: z.enum(["deposit", "withdraw"]).describe("which side to quote — required, there is no default"),
239
- },
240
- }, guarded(async ({ vault: symbol, account, amount_usdc, direction }) => {
241
- const { vault, client } = clientFor(symbol);
242
- // 🔴 The tag is emitted from INSIDE each branch, beside the fields that branch produces —
243
- // never `{ direction, ...quote }` from the input argument. Measured in review: with the tag
244
- // taken from the input, swapping these two branches left `tsc -b` clean and all 61 tests
245
- // passing, and the result read `{ direction: "deposit", sharesToBurn: … }` — the tag said
246
- // deposit while the body was a withdrawal. A guard derived from the wrong side of the thing
247
- // it guards cannot detect the bug it exists for. Emitted here, tag and body are consistent
248
- // BY CONSTRUCTION; a swapped route is then wrong about the REQUEST, which the handler test
249
- // catches by asserting requested === returned, and never lying about the BODY.
250
- if (direction === "deposit") {
251
- return text({
252
- direction: "deposit",
253
- ...commitsMoney(vault),
254
- ...(await quoteDeposit({ vault, depositor: account, assetsHuman: amount_usdc, client })),
255
- });
256
- }
257
- return text({ direction: "withdraw", ...(await quoteWithdraw({ vault, owner: account, assetsHuman: amount_usdc, client })) });
258
- }));
259
- server.registerTool("earn_prepare_deposit", {
260
- title: "Prepare an unsigned deposit",
261
- 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.",
262
- inputSchema: {
263
- vault: vaultArg,
264
- account: accountArg.describe("the depositing account — the one that signs both calls; step 2's allowance precondition is read for it"),
265
- amount_usdc: amountArg,
266
- receiver: addressArg.describe("where the SHARES land — usually the account, not necessarily"),
267
- },
268
- }, guarded(async ({ vault: symbol, account, amount_usdc, receiver }) => {
269
- const vault = supportedVault(symbol);
270
- return unsigned(buildDeposit(vault, { assetsHuman: amount_usdc, receiver, account }), vault);
271
- }));
272
- server.registerTool("earn_prepare_withdraw", {
273
- title: "Prepare an unsigned withdrawal",
274
- 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.",
275
- inputSchema: {
276
- vault: vaultArg,
277
- receiver: addressArg.describe("where the USDC lands — NOT necessarily the account"),
278
- account: accountArg.describe("whose shares are burnt"),
279
- amount_usdc: amountArg.optional(),
280
- all: z.boolean().optional(),
281
- shares_exact: z.string().regex(/^\d+(\.\d+)?$/).optional(),
282
- },
283
- }, guarded(async ({ vault: symbol, receiver, account, amount_usdc, all, shares_exact }) => {
284
- const vault = supportedVault(symbol);
285
- // ⚠️ `receiver` and `account` are DIFFERENT slots and both are addresses, so a transposition
286
- // here type-checks. `account` is the owner whose shares burn; `receiver` is the payee.
287
- if (all) {
288
- if (!shares_exact)
289
- throw new Error("all=true requires shares_exact (copy earn_balance.sharesExact verbatim)");
290
- return unsigned(buildWithdraw(vault, { receiver, owner: account, all: true, sharesExact: shares_exact }));
291
- }
292
- if (!amount_usdc)
293
- throw new Error("provide amount_usdc, or all=true with shares_exact");
294
- return unsigned(buildWithdraw(vault, { receiver, owner: account, assetsHuman: amount_usdc }));
295
- }));
296
- server.registerTool("earn_balance", {
297
- title: "Earn position",
298
- 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, `exit.instantLiquidity` is the vault's own liquid balance of the asset, chassis-specific in both directions — a Fusion vault without instant-withdrawal fuses pays only from it, so there it is the ceiling and `usdcValue` can exceed `exitableNow` by 10x while `maxWithdraw()` — `exit.maxWithdrawSays` — reports the larger one; a Morpho V2 vault holds almost none and still pays out of its markets, so there a near-zero `instantLiquidity` is not a ceiling and `exitableNow` is the verdict), 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.",
299
- inputSchema: {
300
- vault: vaultArg,
301
- account: accountArg,
302
- 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"),
303
- 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"),
304
- },
305
- }, guarded(async ({ vault: symbol, account, lookback_blocks, max_log_requests }) => {
306
- const vault = supportedVault(symbol);
307
- const logsUrl = logsRpcUrlFromEnv(vault.chainId);
308
- const client = makePublicClient(vault.chainId, logsUrl);
309
- // `logsFallbackUrlFromEnv` returns undefined when the operator opted out or when the fallback
310
- // would be the primary itself — the wiring is a one-liner precisely so it can be unit-tested
311
- // (measured in review: mutating this line to `undefined` left every position-layer test green;
312
- // `server.unit.test.ts` is what fails now).
313
- const fallbackUrl = logsFallbackUrlFromEnv(vault.chainId, logsUrl);
314
- const fallbackClient = fallbackUrl === undefined ? undefined : makePublicClient(vault.chainId, fallbackUrl);
315
- return text(await getPosition({
316
- vault,
317
- principal: account,
318
- client,
319
- ...(fallbackClient ? { fallbackClient } : {}),
320
- ...(lookback_blocks === undefined ? {} : { lookbackBlocks: BigInt(lookback_blocks) }),
321
- ...(max_log_requests === undefined ? {} : { maxLogRequests: max_log_requests }),
322
- }));
323
- }));
324
- server.registerTool("earn_claim", {
325
- title: "Claim a queued withdrawal",
326
- 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.",
327
- inputSchema: { receipt_id: z.string() },
328
- }, guarded(async ({ receipt_id }) => text({
329
- receipt_id,
330
- status: "nothing_to_claim",
331
- 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.",
332
- })));
333
- return server;
334
- }
335
- async function main() {
336
- const server = buildServer();
337
- await server.connect(new StdioServerTransport());
338
- }
339
- /**
340
- * True only when THIS module is the file Node was asked to run. The comparison is by resolved path,
341
- * not by name: an earlier guard tested `process.argv[1]` against `/server\.(ts|mjs|js)$/`, which is
342
- * the basename of whatever was invoked — so the published bin (`treasury-mcp`, a symlink npm makes)
343
- * never matched and exited silently (#22), while any unrelated script named `*server.mjs` that merely
344
- * imported this module matched and seized stdio. Node resolves the main module's symlink before
345
- * evaluating it, so `import.meta.url` is already the real path and the two sides agree for a bin.
346
- * Anything unresolvable is treated as "not the entry point": the module loads and does nothing.
347
- */
348
- function isEntryPoint() {
349
- const invoked = process.argv[1];
350
- if (!invoked)
351
- return false;
352
- try {
353
- return realpathSync(invoked) === realpathSync(fileURLToPath(import.meta.url));
354
- }
355
- catch {
356
- return false;
357
- }
358
- }
359
- if (isEntryPoint()) {
360
- main().catch((e) => {
361
- // Defence-in-depth: HARDENED, NOT TESTED. main() only builds the server and connects a stdio
362
- // transport — every RPC URL is resolved inside a handler body, so nothing reachable here can
363
- // carry one. This guard exists so that stays true if main() ever grows.
364
- process.stderr.write(`treasury mcp: ${redactEndpoints(String(e))}\n`);
365
- process.exit(1);
366
- });
367
- }
368
- //# sourceMappingURL=server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}