@ironwallet/mcp-server 1.0.0-preprod.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 (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/assets/knight.png +0 -0
  4. package/assets/wordmark.svg +20 -0
  5. package/dist/api/auth.d.ts +20 -0
  6. package/dist/api/auth.js +92 -0
  7. package/dist/api/auth.js.map +1 -0
  8. package/dist/api/balances.d.ts +25 -0
  9. package/dist/api/balances.js +565 -0
  10. package/dist/api/balances.js.map +1 -0
  11. package/dist/api/http.d.ts +34 -0
  12. package/dist/api/http.js +277 -0
  13. package/dist/api/http.js.map +1 -0
  14. package/dist/api/relay.d.ts +49 -0
  15. package/dist/api/relay.js +194 -0
  16. package/dist/api/relay.js.map +1 -0
  17. package/dist/api/rpc.d.ts +10 -0
  18. package/dist/api/rpc.js +26 -0
  19. package/dist/api/rpc.js.map +1 -0
  20. package/dist/api/swap.d.ts +134 -0
  21. package/dist/api/swap.js +554 -0
  22. package/dist/api/swap.js.map +1 -0
  23. package/dist/cli.d.ts +6 -0
  24. package/dist/cli.js +20 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/config.d.ts +91 -0
  27. package/dist/config.js +175 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/generated/env-config.d.ts +5 -0
  30. package/dist/generated/env-config.js +23 -0
  31. package/dist/generated/env-config.js.map +1 -0
  32. package/dist/generated/env-profile.d.ts +15 -0
  33. package/dist/generated/env-profile.js +2 -0
  34. package/dist/generated/env-profile.js.map +1 -0
  35. package/dist/keystore/crypto.d.ts +17 -0
  36. package/dist/keystore/crypto.js +57 -0
  37. package/dist/keystore/crypto.js.map +1 -0
  38. package/dist/keystore/store.d.ts +45 -0
  39. package/dist/keystore/store.js +224 -0
  40. package/dist/keystore/store.js.map +1 -0
  41. package/dist/keystore/types.d.ts +31 -0
  42. package/dist/keystore/types.js +2 -0
  43. package/dist/keystore/types.js.map +1 -0
  44. package/dist/local-secrets.d.ts +16 -0
  45. package/dist/local-secrets.js +73 -0
  46. package/dist/local-secrets.js.map +1 -0
  47. package/dist/log.d.ts +30 -0
  48. package/dist/log.js +323 -0
  49. package/dist/log.js.map +1 -0
  50. package/dist/passphrase.d.ts +6 -0
  51. package/dist/passphrase.js +10 -0
  52. package/dist/passphrase.js.map +1 -0
  53. package/dist/policy.d.ts +22 -0
  54. package/dist/policy.js +108 -0
  55. package/dist/policy.js.map +1 -0
  56. package/dist/server.d.ts +6 -0
  57. package/dist/server.js +38 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/signing/bitcoin.d.ts +18 -0
  60. package/dist/signing/bitcoin.js +84 -0
  61. package/dist/signing/bitcoin.js.map +1 -0
  62. package/dist/signing/dispatch.d.ts +7 -0
  63. package/dist/signing/dispatch.js +35 -0
  64. package/dist/signing/dispatch.js.map +1 -0
  65. package/dist/signing/evm.d.ts +16 -0
  66. package/dist/signing/evm.js +59 -0
  67. package/dist/signing/evm.js.map +1 -0
  68. package/dist/signing/index.d.ts +10 -0
  69. package/dist/signing/index.js +57 -0
  70. package/dist/signing/index.js.map +1 -0
  71. package/dist/signing/solana.d.ts +18 -0
  72. package/dist/signing/solana.js +106 -0
  73. package/dist/signing/solana.js.map +1 -0
  74. package/dist/signing/swap.d.ts +10 -0
  75. package/dist/signing/swap.js +114 -0
  76. package/dist/signing/swap.js.map +1 -0
  77. package/dist/signing/ton.d.ts +33 -0
  78. package/dist/signing/ton.js +166 -0
  79. package/dist/signing/ton.js.map +1 -0
  80. package/dist/signing/tron.d.ts +11 -0
  81. package/dist/signing/tron.js +39 -0
  82. package/dist/signing/tron.js.map +1 -0
  83. package/dist/signing/types.d.ts +23 -0
  84. package/dist/signing/types.js +2 -0
  85. package/dist/signing/types.js.map +1 -0
  86. package/dist/signing/xrp.d.ts +11 -0
  87. package/dist/signing/xrp.js +122 -0
  88. package/dist/signing/xrp.js.map +1 -0
  89. package/dist/tools/helpers.d.ts +42 -0
  90. package/dist/tools/helpers.js +80 -0
  91. package/dist/tools/helpers.js.map +1 -0
  92. package/dist/tools/index.d.ts +7 -0
  93. package/dist/tools/index.js +16 -0
  94. package/dist/tools/index.js.map +1 -0
  95. package/dist/tools/swap.d.ts +6 -0
  96. package/dist/tools/swap.js +343 -0
  97. package/dist/tools/swap.js.map +1 -0
  98. package/dist/tools/transfer.d.ts +6 -0
  99. package/dist/tools/transfer.js +284 -0
  100. package/dist/tools/transfer.js.map +1 -0
  101. package/dist/tools/wallets.d.ts +6 -0
  102. package/dist/tools/wallets.js +79 -0
  103. package/dist/tools/wallets.js.map +1 -0
  104. package/dist/wallet/derive.d.ts +53 -0
  105. package/dist/wallet/derive.js +233 -0
  106. package/dist/wallet/derive.js.map +1 -0
  107. package/dist/web/manager.d.ts +15 -0
  108. package/dist/web/manager.js +444 -0
  109. package/dist/web/manager.js.map +1 -0
  110. package/package.json +54 -0
@@ -0,0 +1,444 @@
1
+ /**
2
+ * Local browser-based wallet manager. An MCP tool starts this and hands the
3
+ * user a URL; the seed phrase is only ever typed into / shown by this page in
4
+ * the user's browser and never crosses the agent boundary.
5
+ *
6
+ * Security posture:
7
+ * - binds 127.0.0.1 only,
8
+ * - all routes live under an unguessable random token path (a capability),
9
+ * - the server self-destructs after a period of inactivity.
10
+ *
11
+ * The keystore passphrase is resolved locally (generated on first use). Forms
12
+ * only ask for wallet name / mnemonic / count.
13
+ */
14
+ import { createServer } from "node:http";
15
+ import { randomBytes } from "node:crypto";
16
+ import { readFileSync } from "node:fs";
17
+ import { fileURLToPath } from "node:url";
18
+ import { loadKeystore, importWallet, createWallets, revealMnemonic, markBackedUp, } from "../keystore/store.js";
19
+ import { requirePassphrase } from "../passphrase.js";
20
+ import { logError, logInfo } from "../log.js";
21
+ const INACTIVITY_MS = 15 * 60 * 1000;
22
+ let current = null;
23
+ let inactivityTimer = null;
24
+ function escapeHtml(s) {
25
+ return s
26
+ .replace(/&/g, "&")
27
+ .replace(/</g, "&lt;")
28
+ .replace(/>/g, "&gt;")
29
+ .replace(/"/g, "&quot;");
30
+ }
31
+ function armInactivityTimer() {
32
+ if (inactivityTimer)
33
+ clearTimeout(inactivityTimer);
34
+ inactivityTimer = setTimeout(() => shutdown(), INACTIVITY_MS);
35
+ inactivityTimer.unref?.();
36
+ }
37
+ function shutdown() {
38
+ if (inactivityTimer)
39
+ clearTimeout(inactivityTimer);
40
+ inactivityTimer = null;
41
+ const c = current;
42
+ current = null;
43
+ c?.server.close();
44
+ }
45
+ async function readForm(req) {
46
+ const chunks = [];
47
+ for await (const chunk of req)
48
+ chunks.push(chunk);
49
+ const body = Buffer.concat(chunks).toString("utf8");
50
+ const params = new URLSearchParams(body);
51
+ const out = {};
52
+ for (const [k, v] of params)
53
+ out[k] = v;
54
+ return out;
55
+ }
56
+ /**
57
+ * Visual language mirrors the Ironwallet mobile app (lib/themes):
58
+ * - surfaces #FAFAFA / cards #FFFFFF, text #1B2028 / muted #9498A5,
59
+ * - signature UI gradient #3650AB → #2A81A6 (buttons, accents),
60
+ * - logo gradient #2C32BA → #0BB4EA (wordmark),
61
+ * - 10px cards, 14px inputs/buttons, 48px button height,
62
+ * - full dark theme (#1B2028 bg / #31353F cards) via prefers-color-scheme.
63
+ */
64
+ const STYLE = `
65
+ :root {
66
+ --bg:#FAFAFA; --surface:#FFFFFF; --surface-2:#F4F5F7;
67
+ --text:#1B2028; --text-2:#686869; --muted:#9498A5;
68
+ --border:#E5E8EB; --primary:#396DC3;
69
+ --ui-grad:linear-gradient(135deg,#3650AB 0%,#2A81A6 100%);
70
+ --logo-grad:linear-gradient(135deg,#2C32BA 0%,#0BB4EA 100%);
71
+ --success:#51BF9D; --success-bg:#DCF2EB;
72
+ --warning:#F18827; --warning-bg:#FCE7D4;
73
+ --danger:#F04E58;
74
+ --shadow:0 1px 2px rgba(27,32,40,.06), 0 8px 24px rgba(27,32,40,.06);
75
+ }
76
+ @media (prefers-color-scheme: dark) {
77
+ :root {
78
+ --bg:#1B2028; --surface:#31353F; --surface-2:#272B33;
79
+ --text:#FFFFFF; --text-2:#E5E8EB; --muted:#9498A5;
80
+ --border:#3A3F4A; --primary:#3C72C9;
81
+ --logo-grad:linear-gradient(135deg,#2B2FA0 0%,#169FCA 100%);
82
+ --success-bg:#20362F; --warning-bg:#3A2A18;
83
+ --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px rgba(0,0,0,.25);
84
+ }
85
+ }
86
+ * { box-sizing:border-box; }
87
+ body {
88
+ font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
89
+ background:var(--bg); color:var(--text); margin:0;
90
+ padding:32px 16px 64px; line-height:1.45; -webkit-font-smoothing:antialiased;
91
+ }
92
+ .wrap { max-width:760px; margin:0 auto; }
93
+ .hero {
94
+ display:flex; flex-direction:column; align-items:center; text-align:center;
95
+ gap:6px; padding:12px 0 20px; margin-bottom:4px;
96
+ }
97
+ .hero .wordmark { height:34px; width:auto; display:block; }
98
+ .hero .knight {
99
+ height:200px; width:auto; margin:6px 0 2px;
100
+ filter:drop-shadow(0 12px 24px rgba(27,32,40,.14));
101
+ }
102
+ .hero-tag { color:var(--text-2); font-size:14px; margin:0; max-width:360px; }
103
+ @media (max-width:520px) { .hero .knight { height:168px; } }
104
+ h2 { font-size:16px; font-weight:600; margin:0 0 4px; }
105
+ .section-hint { color:var(--muted); font-size:13px; margin:0 0 14px; }
106
+ .card {
107
+ background:var(--surface); border:1px solid var(--border); border-radius:14px;
108
+ padding:18px 20px; margin:16px 0; box-shadow:var(--shadow);
109
+ }
110
+ .ok { color:var(--success); } .warn { color:var(--warning); } .err { color:var(--danger); }
111
+
112
+ /* wallet list */
113
+ .wallet { padding:14px 0; border-bottom:1px solid var(--border); }
114
+ .wallet:last-child { border-bottom:0; padding-bottom:0; }
115
+ .wallet:first-child { padding-top:0; }
116
+ .wallet-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:10px; }
117
+ .wallet-name { font-size:16px; font-weight:600; display:flex; align-items:center; gap:10px; }
118
+ .avatar {
119
+ width:28px; height:28px; border-radius:9px; background:var(--ui-grad);
120
+ display:grid; place-items:center; color:#fff; font-size:13px; font-weight:700; flex:none;
121
+ }
122
+ .badge {
123
+ font-size:11px; font-weight:600; padding:3px 9px; border-radius:999px;
124
+ display:inline-flex; align-items:center; gap:5px;
125
+ }
126
+ .badge.ok { background:var(--success-bg); color:var(--success); }
127
+ .badge.warn { background:var(--warning-bg); color:var(--warning); }
128
+
129
+ .addr { display:flex; align-items:center; gap:10px; padding:8px 0; }
130
+ .net {
131
+ font-size:11px; font-weight:700; color:var(--muted); width:44px; flex:none;
132
+ text-transform:uppercase; letter-spacing:.4px;
133
+ }
134
+ .addr code {
135
+ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
136
+ background:var(--surface-2); border:1px solid var(--border); border-radius:9px;
137
+ padding:8px 10px; font-size:13px; font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
138
+ color:var(--text);
139
+ }
140
+ .copy {
141
+ flex:none; margin:0; padding:8px 12px; font-size:12px; font-weight:600;
142
+ background:var(--surface-2); color:var(--primary); border:1px solid var(--border);
143
+ border-radius:9px; cursor:pointer;
144
+ }
145
+ .copy:hover { border-color:var(--primary); }
146
+ .copy.copied { color:var(--success); border-color:var(--success); }
147
+
148
+ label { display:block; font-size:13px; color:var(--text-2); margin:14px 0 6px; }
149
+ input, textarea, button { font:inherit; }
150
+ input, textarea {
151
+ width:100%; background:var(--surface-2); color:var(--text);
152
+ border:1px solid var(--border); border-radius:14px; padding:11px 14px;
153
+ }
154
+ input:focus, textarea:focus { outline:none; border-color:var(--primary); }
155
+ textarea { min-height:72px; resize:vertical; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
156
+ button.btn {
157
+ margin-top:16px; height:48px; padding:0 22px; background:var(--ui-grad); color:#fff;
158
+ border:0; border-radius:14px; font-size:15px; font-weight:600; cursor:pointer;
159
+ box-shadow:var(--shadow);
160
+ }
161
+ button.btn:hover { filter:brightness(1.05); }
162
+ button.ghost {
163
+ margin:0; height:auto; padding:8px 14px; background:transparent; color:var(--primary);
164
+ border:1px solid var(--border); border-radius:10px; font-size:13px; font-weight:600;
165
+ cursor:pointer; box-shadow:none;
166
+ }
167
+ button.ghost:hover { border-color:var(--primary); }
168
+
169
+ code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
170
+ ol.words {
171
+ columns:3; column-gap:14px; margin:6px 0 0; padding:0; list-style:none; counter-reset:w;
172
+ }
173
+ ol.words li {
174
+ counter-increment:w; display:flex; align-items:center; gap:8px; margin:6px 0;
175
+ background:var(--surface-2); border:1px solid var(--border); border-radius:10px;
176
+ padding:8px 10px; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:14px;
177
+ }
178
+ ol.words li::before {
179
+ content:counter(w); color:var(--muted); font-size:11px; font-family:inherit;
180
+ min-width:16px; text-align:right;
181
+ }
182
+ .empty { color:var(--muted); font-size:14px; text-align:center; padding:18px 0; }
183
+ a.back { color:var(--primary); font-size:14px; font-weight:600; text-decoration:none; }
184
+ a.back:hover { text-decoration:underline; }
185
+ @media (max-width:480px) { ol.words { columns:2; } .net { width:40px; } }
186
+ `;
187
+ const COPY_SCRIPT = `
188
+ <script>
189
+ document.addEventListener('click', function(e){
190
+ var b = e.target.closest('.copy'); if(!b) return;
191
+ navigator.clipboard.writeText(b.dataset.addr).then(function(){
192
+ var t = b.textContent; b.textContent = 'Copied'; b.classList.add('copied');
193
+ setTimeout(function(){ b.textContent = t; b.classList.remove('copied'); }, 1200);
194
+ });
195
+ });
196
+ </script>`;
197
+ function layout(token, title, inner, showBack = true) {
198
+ const back = showBack
199
+ ? `<p style="margin-top:28px"><a class="back" href="/${token}">&larr; Back to wallets</a></p>`
200
+ : "";
201
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8">
202
+ <meta name="viewport" content="width=device-width, initial-scale=1">
203
+ <title>${escapeHtml(title)}</title><style>${STYLE}</style></head><body>
204
+ <div class="wrap">
205
+ <div class="hero">
206
+ <img class="wordmark" src="/${token}/assets/wordmark.svg" alt="Ironwallet">
207
+ <img class="knight" src="/${token}/assets/knight.png" alt="" aria-hidden="true">
208
+ <p class="hero-tag">Local wallet manager — keys never leave this machine</p>
209
+ </div>
210
+ ${inner}
211
+ ${back}
212
+ </div>${COPY_SCRIPT}
213
+ </body></html>`;
214
+ }
215
+ function initials(name) {
216
+ const s = name.trim();
217
+ return (s.slice(0, 2) || "IW").toUpperCase();
218
+ }
219
+ function walletCard(token, w) {
220
+ const backed = w.backedUp
221
+ ? '<span class="badge ok">Backed up</span>'
222
+ : '<span class="badge warn">Not backed up</span>';
223
+ const addrs = renderAddresses(w.addresses);
224
+ return `<div class="wallet">
225
+ <div class="wallet-head">
226
+ <div class="wallet-name"><span class="avatar">${escapeHtml(initials(w.name))}</span>${escapeHtml(w.name)}</div>
227
+ <div style="display:flex;align-items:center;gap:10px">
228
+ ${backed}
229
+ <form method="POST" action="/${token}/backup" style="margin:0">
230
+ <input type="hidden" name="name" value="${escapeHtml(w.name)}">
231
+ <button class="ghost" type="submit">Reveal phrase</button>
232
+ </form>
233
+ </div>
234
+ </div>
235
+ ${addrs}
236
+ </div>`;
237
+ }
238
+ function netLabel(net) {
239
+ const map = { ethereum: "EVM", tron: "TRX" };
240
+ return map[net] ?? net.slice(0, 4).toUpperCase();
241
+ }
242
+ function addressRow(net, addr) {
243
+ return `<div class="addr">
244
+ <span class="net">${escapeHtml(netLabel(net))}</span>
245
+ <code title="${escapeHtml(addr)}">${escapeHtml(addr)}</code>
246
+ <button class="copy" data-addr="${escapeHtml(addr)}" type="button">Copy</button>
247
+ </div>`;
248
+ }
249
+ /**
250
+ * Render one row per *unique* address. All EVM chains share the same address, so
251
+ * collapsing avoids repeating the same value 7 times; the first network that
252
+ * produced a given address supplies the label (ethereum → EVM, tron → TRX).
253
+ */
254
+ function renderAddresses(addresses) {
255
+ const seen = new Set();
256
+ const rows = [];
257
+ for (const [net, addr] of Object.entries(addresses)) {
258
+ if (!addr || seen.has(addr))
259
+ continue;
260
+ seen.add(addr);
261
+ rows.push(addressRow(net, addr));
262
+ }
263
+ return rows.join("");
264
+ }
265
+ function dashboard(token, notice = "") {
266
+ const ks = loadKeystore();
267
+ const list = ks.wallets.length
268
+ ? ks.wallets.map((w) => walletCard(token, w)).join("")
269
+ : '<div class="empty">No wallets yet. Import or create one below.</div>';
270
+ return layout(token, "Ironwallet manager", `${notice}
271
+ <div class="card">
272
+ <h2>Your wallets</h2>
273
+ <p class="section-hint">${ks.wallets.length} wallet${ks.wallets.length === 1 ? "" : "s"} · tap Copy to grab an address</p>
274
+ ${list}
275
+ </div>
276
+
277
+ <div class="card">
278
+ <h2>Import an existing wallet</h2>
279
+ <p class="section-hint">Your recovery phrase is encrypted locally and never sent anywhere.</p>
280
+ <form method="POST" action="/${token}/import">
281
+ <label>Name (optional)</label>
282
+ <input name="name" placeholder="e.g. trading" autocomplete="off">
283
+ <label>Recovery phrase (12 or 24 words)</label>
284
+ <textarea name="mnemonic" placeholder="word1 word2 …" autocomplete="off" spellcheck="false"></textarea>
285
+ <button class="btn" type="submit">Import wallet</button>
286
+ </form>
287
+ </div>
288
+
289
+ <div class="card">
290
+ <h2>Create new wallet(s)</h2>
291
+ <p class="section-hint">Fresh keys are generated on this machine. Back them up right after.</p>
292
+ <form method="POST" action="/${token}/create">
293
+ <label>How many</label>
294
+ <input name="count" type="number" min="1" max="50" value="1">
295
+ <label>Name prefix (optional)</label>
296
+ <input name="prefix" placeholder="e.g. agent-hot" autocomplete="off">
297
+ <button class="btn" type="submit">Create wallet</button>
298
+ </form>
299
+ </div>`, false);
300
+ }
301
+ function wordsBlock(mnemonic) {
302
+ const words = mnemonic.split(/\s+/).filter(Boolean);
303
+ return `<ol class="words">${words
304
+ .map((w) => `<li>${escapeHtml(w)}</li>`)
305
+ .join("")}</ol>`;
306
+ }
307
+ function addressesBlock(addresses) {
308
+ return renderAddresses(addresses);
309
+ }
310
+ function html(res, status, body) {
311
+ res.writeHead(status, {
312
+ "Content-Type": "text/html; charset=utf-8",
313
+ "Cache-Control": "no-store, no-cache, must-revalidate, private",
314
+ Pragma: "no-cache",
315
+ Expires: "0",
316
+ "X-Frame-Options": "DENY",
317
+ "X-Content-Type-Options": "nosniff",
318
+ "Referrer-Policy": "no-referrer",
319
+ "Content-Security-Policy": "default-src 'none'; img-src 'self'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'",
320
+ });
321
+ res.end(body);
322
+ }
323
+ /** Static brand assets bundled with the package (see package.json "files"). */
324
+ const ASSETS = {
325
+ "wordmark.svg": { file: "wordmark.svg", type: "image/svg+xml" },
326
+ "knight.png": { file: "knight.png", type: "image/png" },
327
+ };
328
+ function serveAsset(res, name) {
329
+ const asset = ASSETS[name];
330
+ if (!asset)
331
+ return false;
332
+ try {
333
+ // compiled at dist/web/manager.js → package root is two levels up.
334
+ const path = fileURLToPath(new URL(`../../assets/${asset.file}`, import.meta.url));
335
+ const buf = readFileSync(path);
336
+ res.writeHead(200, {
337
+ "Content-Type": asset.type,
338
+ "Cache-Control": "max-age=3600",
339
+ });
340
+ res.end(buf);
341
+ return true;
342
+ }
343
+ catch {
344
+ return false;
345
+ }
346
+ }
347
+ /** Start the manager (or reuse a running one) and return its base URL. */
348
+ export async function ensureManager() {
349
+ if (current) {
350
+ armInactivityTimer();
351
+ logInfo("manager.reuse", { url: current.url });
352
+ return current.url;
353
+ }
354
+ const token = randomBytes(16).toString("hex");
355
+ const base = `/${token}`;
356
+ logInfo("manager.start", { base });
357
+ const server = createServer((req, res) => {
358
+ armInactivityTimer();
359
+ const url = (req.url ?? "").split("?")[0];
360
+ if (!url.startsWith(base)) {
361
+ html(res, 404, "not found");
362
+ return;
363
+ }
364
+ const sub = url.slice(base.length) || "/";
365
+ const method = req.method ?? "GET";
366
+ logInfo("manager.request", { method, path: sub });
367
+ void (async () => {
368
+ try {
369
+ if (method === "GET" && sub === "/") {
370
+ html(res, 200, dashboard(token));
371
+ return;
372
+ }
373
+ if (method === "GET" && sub.startsWith("/assets/")) {
374
+ const name = sub.slice("/assets/".length);
375
+ if (serveAsset(res, name))
376
+ return;
377
+ html(res, 404, "not found");
378
+ return;
379
+ }
380
+ if (method === "POST" && sub === "/import") {
381
+ const form = await readForm(req);
382
+ const created = importWallet(form.mnemonic ?? "", requirePassphrase(), form.name?.trim() || undefined);
383
+ logInfo("manager.import.ok", { name: created.name, addresses: created.addresses });
384
+ html(res, 200, layout(token, "Imported", `<div class="card"><h2 style="margin-top:0" class="ok">Imported "${escapeHtml(created.name)}"</h2><p>Addresses:</p>${addressesBlock(created.addresses)}</div>`));
385
+ return;
386
+ }
387
+ if (method === "POST" && sub === "/create") {
388
+ const form = await readForm(req);
389
+ const count = Math.max(1, Math.min(50, parseInt(form.count ?? "1", 10) || 1));
390
+ const created = createWallets(count, requirePassphrase(), {
391
+ namePrefix: form.prefix?.trim() || undefined,
392
+ revealMnemonic: true,
393
+ });
394
+ const blocks = created
395
+ .map((c) => `<div class="card"><h2 style="margin-top:0">${escapeHtml(c.name)}</h2><p class="warn">Write these words down offline. The wallet stays marked as not backed up until you use Reveal phrase.</p>${wordsBlock(c.mnemonic ?? "")}<p>Addresses:</p>${addressesBlock(c.addresses)}</div>`)
396
+ .join("");
397
+ logInfo("manager.create.ok", {
398
+ count: created.length,
399
+ names: created.map((c) => c.name),
400
+ });
401
+ html(res, 200, layout(token, "Created", blocks));
402
+ return;
403
+ }
404
+ if (method === "POST" && sub === "/backup") {
405
+ const form = await readForm(req);
406
+ const name = form.name ?? "";
407
+ const mnemonic = revealMnemonic(name, requirePassphrase());
408
+ markBackedUp(name);
409
+ logInfo("manager.backup.ok", {
410
+ name,
411
+ wordCount: mnemonic.trim().split(/\s+/).length,
412
+ });
413
+ html(res, 200, layout(token, "Backup", `<div class="card"><h2 style="margin-top:0">Recovery phrase for "${escapeHtml(name)}"</h2><p class="warn">Anyone with these words controls the funds. Keep them offline.</p>${wordsBlock(mnemonic)}</div>`));
414
+ return;
415
+ }
416
+ html(res, 404, "not found");
417
+ }
418
+ catch (e) {
419
+ logError("manager.request.fail", e, { method, path: sub });
420
+ const message = e instanceof Error ? e.message : String(e);
421
+ html(res, 400, layout(token, "Error", `<div class="card"><p class="err">Error: ${escapeHtml(message)}</p></div>`));
422
+ }
423
+ })();
424
+ });
425
+ return new Promise((resolve, reject) => {
426
+ server.on("error", (e) => {
427
+ logError("manager.listen.fail", e, {});
428
+ reject(e);
429
+ });
430
+ server.listen(0, "127.0.0.1", () => {
431
+ const addr = server.address();
432
+ if (!addr || typeof addr !== "object") {
433
+ reject(new Error("failed to bind manager server"));
434
+ return;
435
+ }
436
+ const url = `http://127.0.0.1:${addr.port}${base}`;
437
+ current = { url, server };
438
+ armInactivityTimer();
439
+ logInfo("manager.listen.ok", { url });
440
+ resolve(url);
441
+ });
442
+ });
443
+ }
444
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/web/manager.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ironwallet/mcp-server",
3
+ "version": "1.0.0-preprod.0",
4
+ "license": "MIT",
5
+ "description": "Local MCP server for Ironwallet: seed-compatible wallet management, transfers and Swap Proxy swaps for EVM, Tron, Bitcoin, Litecoin, Doge, Solana, XRP and TON.",
6
+ "homepage": "https://ironwallet.io/ai",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ironwallet-ai/ironwallet-agent-kit.git",
10
+ "directory": "packages/mcp-server"
11
+ },
12
+ "type": "module",
13
+ "bin": {
14
+ "ironwallet-mcp": "dist/cli.js"
15
+ },
16
+ "main": "dist/server.js",
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "start": "node dist/cli.js",
20
+ "dev": "tsx src/cli.ts",
21
+ "prepack": "npm run build"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "assets",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "dependencies": {
33
+ "@modelcontextprotocol/sdk": "^1.19.1",
34
+ "@noble/curves": "^2.2.0",
35
+ "@noble/hashes": "^2.2.0",
36
+ "@scure/base": "^2.2.0",
37
+ "@scure/bip32": "^1.7.0",
38
+ "@scure/btc-signer": "^2.2.0",
39
+ "@ton/crypto": "^3.3.0",
40
+ "@ton/ton": "^16.3.0",
41
+ "bip39": "^3.1.0",
42
+ "bs58": "^6.0.0",
43
+ "bs58check": "^4.0.0",
44
+ "ethers": "^6.15.0",
45
+ "ripple-binary-codec": "^2.8.0",
46
+ "ripple-keypairs": "^3.0.0",
47
+ "zod": "^3.25.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.10.0",
51
+ "tsx": "^4.19.0",
52
+ "typescript": "^5.7.0"
53
+ }
54
+ }