@agentwonderland/mcp 0.1.29 → 0.1.31

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.
@@ -13,6 +13,23 @@ import type { Keypair } from "@solana/web3.js";
13
13
  * Check whether the OWS native module can be loaded.
14
14
  */
15
15
  export declare function isOwsAvailable(): Promise<boolean>;
16
+ /**
17
+ * Heuristic: is this platform likely to have a prebuilt OWS binary?
18
+ * OWS ships glibc prebuilds for {darwin, linux, win32} x {x64, arm64}.
19
+ * Musl-libc (Alpine) and other libcs have no prebuilds.
20
+ */
21
+ export declare function platformSupportsOws(): boolean;
22
+ export interface OwsInstallResult {
23
+ ok: boolean;
24
+ message: string;
25
+ needsRestart?: boolean;
26
+ }
27
+ /**
28
+ * Attempt to install @open-wallet-standard/core into the MCP package's own
29
+ * node_modules. Avoids sudo for npx-based installs; may require sudo for a
30
+ * global MCP install.
31
+ */
32
+ export declare function installOws(): Promise<OwsInstallResult>;
16
33
  /**
17
34
  * Build a viem-compatible `LocalAccount` backed by an OWS wallet.
18
35
  *
@@ -71,6 +71,81 @@ export async function isOwsAvailable() {
71
71
  return false;
72
72
  }
73
73
  }
74
+ /**
75
+ * Heuristic: is this platform likely to have a prebuilt OWS binary?
76
+ * OWS ships glibc prebuilds for {darwin, linux, win32} x {x64, arm64}.
77
+ * Musl-libc (Alpine) and other libcs have no prebuilds.
78
+ */
79
+ export function platformSupportsOws() {
80
+ const ok = new Set([
81
+ "darwin-x64", "darwin-arm64",
82
+ "linux-x64", "linux-arm64",
83
+ "win32-x64", "win32-arm64",
84
+ ]);
85
+ if (!ok.has(`${process.platform}-${process.arch}`))
86
+ return false;
87
+ // On Linux, distinguish glibc from musl. musl systems have no prebuilt binary.
88
+ if (process.platform === "linux") {
89
+ try {
90
+ // Node exposes the runtime glibc version when linked against glibc;
91
+ // on musl this field is empty.
92
+ const report = process.report;
93
+ const glibc = report?.getReport?.()?.header?.glibcVersionRuntime;
94
+ if (!glibc)
95
+ return false;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ return true;
102
+ }
103
+ /**
104
+ * Attempt to install @open-wallet-standard/core into the MCP package's own
105
+ * node_modules. Avoids sudo for npx-based installs; may require sudo for a
106
+ * global MCP install.
107
+ */
108
+ export async function installOws() {
109
+ if (await isOwsAvailable()) {
110
+ return { ok: true, message: "OWS is already installed." };
111
+ }
112
+ if (!platformSupportsOws()) {
113
+ const label = process.platform === "linux"
114
+ ? `${process.platform}-${process.arch} (likely musl/Alpine)`
115
+ : `${process.platform}-${process.arch}`;
116
+ return {
117
+ ok: false,
118
+ message: `OWS does not ship a prebuilt binary for ${label}. Plaintext storage is the only option on this system. To build from source you'd need glibc + Node build tools (python3, make, node-gyp).`,
119
+ };
120
+ }
121
+ const { execFileSync } = await import("node:child_process");
122
+ const { dirname, resolve } = await import("node:path");
123
+ const { fileURLToPath } = await import("node:url");
124
+ // dist/core/ows-adapter.js → package root is ../../
125
+ const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
126
+ try {
127
+ execFileSync(process.platform === "win32" ? "npm.cmd" : "npm", ["install", "@open-wallet-standard/core", "--no-save", "--no-audit", "--no-fund", "--prefer-offline", "--loglevel=error"], { cwd: pkgRoot, stdio: ["ignore", "pipe", "pipe"], timeout: 120_000 });
128
+ }
129
+ catch (err) {
130
+ const e = err;
131
+ const stderr = e.stderr?.toString() ?? "";
132
+ const hint = stderr.includes("EACCES")
133
+ ? " (permission denied — try: sudo npm install -g @open-wallet-standard/core)"
134
+ : "";
135
+ return {
136
+ ok: false,
137
+ message: `npm install failed: ${(e.message ?? "unknown error").split("\n")[0]}${hint}`,
138
+ };
139
+ }
140
+ if (!(await isOwsAvailable())) {
141
+ return {
142
+ ok: false,
143
+ message: "OWS installed but the module could not be loaded. Restart Claude Code (or whichever MCP host) and retry.",
144
+ needsRestart: true,
145
+ };
146
+ }
147
+ return { ok: true, message: "OWS installed and ready." };
148
+ }
74
149
  /**
75
150
  * Build a viem-compatible `LocalAccount` backed by an OWS wallet.
76
151
  *
@@ -4,7 +4,7 @@ import { getWalletAddress, isCardPaymentEnabled } from "../core/payments.js";
4
4
  import { fetchUsdcBalance } from "../core/balances.js";
5
5
  import { getSettings } from "../core/settings.js";
6
6
  import { getOrCreatePendingCardSetup, formatCardSetupBlocks, getCardCapabilities, pollCardSetup, } from "../core/card-setup.js";
7
- import { isOwsAvailable, createOwsWallet, importKeyToOws, listOwsWallets, listOwsWalletsByChain, } from "../core/ows-adapter.js";
7
+ import { isOwsAvailable, createOwsWallet, importKeyToOws, listOwsWallets, listOwsWalletsByChain, installOws, platformSupportsOws, } from "../core/ows-adapter.js";
8
8
  import { ensureConsumerPrincipal, getConsumerPrincipal } from "../core/principal.js";
9
9
  function text(t) {
10
10
  return { content: [{ type: "text", text: t }] };
@@ -63,13 +63,20 @@ export function registerWalletTools(server) {
63
63
  if (consumerPrincipal) {
64
64
  lines.push("", `Consumer principal: ${consumerPrincipal}`);
65
65
  }
66
+ const plaintextWallets = wallets.filter((w) => w.keyType !== "ows");
67
+ if (plaintextWallets.length > 0) {
68
+ const owsAvailable = await isOwsAvailable();
69
+ if (!owsAvailable && platformSupportsOws()) {
70
+ lines.push("", `⚠ ${plaintextWallets.length} wallet(s) stored in plaintext. Run wallet_setup({ action: "enable-ows" }) to upgrade to encrypted storage.`);
71
+ }
72
+ }
66
73
  return text(lines.join("\n"));
67
74
  });
68
75
  // ── wallet_setup ────────────────────────────────────────────────
69
- server.tool("wallet_setup", "Set up or manage a payment wallet. 'create' makes a new encrypted crypto wallet (OWS); 'import' takes an existing private key. Tempo/Base share one EVM key — a single wallet covers both. Solana uses a separate ed25519 key. For crypto wallet deletion or key rotation, direct users to edit ~/.agentwonderland/config.json or ~/.ows/ manually; never handle key material programmatically.", {
76
+ server.tool("wallet_setup", "Set up or manage a payment wallet. 'create' makes a new crypto wallet (encrypted via OWS if available, otherwise plaintext — run 'enable-ows' to upgrade). 'import' takes an existing private key. 'enable-ows' installs the Open Wallet Standard native module for encrypted at-rest storage. Tempo/Base share one EVM key; Solana uses a separate ed25519 key. NEVER delete or rotate keys programmatically; direct users to edit ~/.agentwonderland/config.json or ~/.ows/ manually.", {
70
77
  action: z
71
- .enum(["create", "import", "add-card", "remove-card"])
72
- .describe("'create' a crypto wallet (recommended), 'import' an existing key, 'add-card'/'remove-card' for credit card (card-backed MPP availability depends on Stripe SPT)"),
78
+ .enum(["create", "import", "add-card", "remove-card", "enable-ows"])
79
+ .describe("'create' a wallet, 'import' an existing key, 'enable-ows' to install encrypted key storage, 'add-card'/'remove-card' for credit card (may be disabled depending on Stripe SPT availability)"),
73
80
  name: z
74
81
  .string()
75
82
  .optional()
@@ -131,6 +138,27 @@ export function registerWalletTools(server) {
131
138
  setCardConfig(null);
132
139
  return text(`Removed ${existing.brand} ****${existing.last4}. Card disconnected from Agent Wonderland.`);
133
140
  }
141
+ // ── Install OWS for encrypted key storage ────────────────
142
+ if (action === "enable-ows") {
143
+ if (await isOwsAvailable()) {
144
+ return text("OWS is already installed — your crypto wallets are stored with AES-256-GCM encryption at rest.");
145
+ }
146
+ if (!platformSupportsOws()) {
147
+ return text(`Your platform (${process.platform}-${process.arch}) does not have a prebuilt OWS binary.\n` +
148
+ "Plaintext storage will remain in effect. To install from source you'd need Node build tools (python3, make, node-gyp).");
149
+ }
150
+ const result = await installOws();
151
+ if (result.ok) {
152
+ const plaintextWallets = getWallets().filter((w) => w.keyType !== "ows");
153
+ const migrationHint = plaintextWallets.length > 0
154
+ ? "\n\nExisting plaintext wallets are NOT auto-migrated. To move them to encrypted storage, re-import each via wallet_setup({ action: \"import\", key: \"<hex>\" }) after OWS is active, then delete the plaintext copy from ~/.agentwonderland/config.json."
155
+ : "";
156
+ return text(`${result.message}\n\n` +
157
+ `New wallets created via wallet_setup({ action: "create" }) will now use encrypted storage.${migrationHint}`);
158
+ }
159
+ return text(`Could not install OWS: ${result.message}\n\n` +
160
+ "Plaintext storage still works. Try again later or install manually: npm install -g @open-wallet-standard/core");
161
+ }
134
162
  // ── Crypto wallet setup ──────────────────────────────────
135
163
  if (action === "import" && !key) {
136
164
  return text("Error: 'key' parameter is required when action is 'import'.");
@@ -206,16 +234,18 @@ export function registerWalletTools(server) {
206
234
  label: walletName,
207
235
  });
208
236
  const principal = await ensureConsumerPrincipal();
237
+ const owsNudge = platformSupportsOws()
238
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
239
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
209
240
  return text([
210
- "Wallet created [plaintext — install OWS for encrypted storage]:",
241
+ "Wallet created:",
211
242
  ` Address: ${kp.publicKey.toBase58()}`,
212
243
  ` Name: ${walletName}`,
213
244
  ` Chains: solana`,
214
245
  ` Consumer principal: ${principal}`,
215
246
  "",
216
247
  "Fund this address with USDC on Solana to start using agents.",
217
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
218
- ].join("\n"));
248
+ ].join("\n") + owsNudge);
219
249
  }
220
250
  const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
221
251
  const privateKey = generatePrivateKey();
@@ -229,16 +259,18 @@ export function registerWalletTools(server) {
229
259
  label: walletName,
230
260
  });
231
261
  const principal = await ensureConsumerPrincipal();
262
+ const owsNudge = platformSupportsOws()
263
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
264
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
232
265
  return text([
233
- "Wallet created [plaintext — install OWS for encrypted storage]:",
266
+ "Wallet created:",
234
267
  ` Address: ${account.address}`,
235
268
  ` Name: ${walletName}`,
236
269
  ` Chains: tempo, base`,
237
270
  ` Consumer principal: ${principal}`,
238
271
  "",
239
272
  `Fund this address with USDC on Tempo or Base to start using agents.`,
240
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
241
- ].join("\n"));
273
+ ].join("\n") + owsNudge);
242
274
  }
243
275
  const walletName = name ?? `aw-${Date.now()}`;
244
276
  const result = await createOwsWallet(walletName, preferredOwsChain);
@@ -304,15 +336,16 @@ export function registerWalletTools(server) {
304
336
  label: walletName,
305
337
  });
306
338
  const principal = await ensureConsumerPrincipal();
339
+ const owsNudge = platformSupportsOws()
340
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
341
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
307
342
  return text([
308
- "Key imported [plaintext — install OWS for encrypted storage]:",
343
+ "Key imported:",
309
344
  ` Address: ${kp.publicKey.toBase58()}`,
310
345
  ` Name: ${walletName}`,
311
346
  ` Chains: solana`,
312
347
  ` Consumer principal: ${principal}`,
313
- "",
314
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
315
- ].join("\n"));
348
+ ].join("\n") + owsNudge);
316
349
  }
317
350
  catch (err) {
318
351
  return text(`Invalid Solana key: ${err instanceof Error ? err.message : String(err)}\n` +
@@ -334,15 +367,16 @@ export function registerWalletTools(server) {
334
367
  label: walletName,
335
368
  });
336
369
  const principal = await ensureConsumerPrincipal();
370
+ const owsNudge = platformSupportsOws()
371
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
372
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
337
373
  return text([
338
- `Key imported [plaintext] \u2014 OWS not available for encrypted storage.`,
374
+ `Key imported:`,
339
375
  ` Address: ${account.address}`,
340
376
  ` Name: ${walletName}`,
341
377
  ` Chains: ${selectedChains.join(", ")}`,
342
378
  ` Consumer principal: ${principal}`,
343
- "",
344
- "Install OWS for encrypted storage: npm install -g @open-wallet-standard/core",
345
- ].join("\n"));
379
+ ].join("\n") + owsNudge);
346
380
  }
347
381
  catch {
348
382
  return text("Error: Invalid private key format.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentwonderland/mcp",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "description": "MCP server for the Agent Wonderland AI agent marketplace",
6
6
  "bin": {
@@ -169,6 +169,97 @@ export async function isOwsAvailable(): Promise<boolean> {
169
169
  }
170
170
  }
171
171
 
172
+ /**
173
+ * Heuristic: is this platform likely to have a prebuilt OWS binary?
174
+ * OWS ships glibc prebuilds for {darwin, linux, win32} x {x64, arm64}.
175
+ * Musl-libc (Alpine) and other libcs have no prebuilds.
176
+ */
177
+ export function platformSupportsOws(): boolean {
178
+ const ok = new Set([
179
+ "darwin-x64", "darwin-arm64",
180
+ "linux-x64", "linux-arm64",
181
+ "win32-x64", "win32-arm64",
182
+ ]);
183
+ if (!ok.has(`${process.platform}-${process.arch}`)) return false;
184
+
185
+ // On Linux, distinguish glibc from musl. musl systems have no prebuilt binary.
186
+ if (process.platform === "linux") {
187
+ try {
188
+ // Node exposes the runtime glibc version when linked against glibc;
189
+ // on musl this field is empty.
190
+ const report = (process as NodeJS.Process & { report?: { getReport?: () => { header?: { glibcVersionRuntime?: string } } } }).report;
191
+ const glibc = report?.getReport?.()?.header?.glibcVersionRuntime;
192
+ if (!glibc) return false;
193
+ } catch {
194
+ return false;
195
+ }
196
+ }
197
+
198
+ return true;
199
+ }
200
+
201
+ export interface OwsInstallResult {
202
+ ok: boolean;
203
+ message: string;
204
+ needsRestart?: boolean;
205
+ }
206
+
207
+ /**
208
+ * Attempt to install @open-wallet-standard/core into the MCP package's own
209
+ * node_modules. Avoids sudo for npx-based installs; may require sudo for a
210
+ * global MCP install.
211
+ */
212
+ export async function installOws(): Promise<OwsInstallResult> {
213
+ if (await isOwsAvailable()) {
214
+ return { ok: true, message: "OWS is already installed." };
215
+ }
216
+
217
+ if (!platformSupportsOws()) {
218
+ const label = process.platform === "linux"
219
+ ? `${process.platform}-${process.arch} (likely musl/Alpine)`
220
+ : `${process.platform}-${process.arch}`;
221
+ return {
222
+ ok: false,
223
+ message: `OWS does not ship a prebuilt binary for ${label}. Plaintext storage is the only option on this system. To build from source you'd need glibc + Node build tools (python3, make, node-gyp).`,
224
+ };
225
+ }
226
+
227
+ const { execFileSync } = await import("node:child_process");
228
+ const { dirname, resolve } = await import("node:path");
229
+ const { fileURLToPath } = await import("node:url");
230
+
231
+ // dist/core/ows-adapter.js → package root is ../../
232
+ const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
233
+
234
+ try {
235
+ execFileSync(
236
+ process.platform === "win32" ? "npm.cmd" : "npm",
237
+ ["install", "@open-wallet-standard/core", "--no-save", "--no-audit", "--no-fund", "--prefer-offline", "--loglevel=error"],
238
+ { cwd: pkgRoot, stdio: ["ignore", "pipe", "pipe"], timeout: 120_000 },
239
+ );
240
+ } catch (err: unknown) {
241
+ const e = err as { stderr?: Buffer; message?: string; code?: string };
242
+ const stderr = e.stderr?.toString() ?? "";
243
+ const hint = stderr.includes("EACCES")
244
+ ? " (permission denied — try: sudo npm install -g @open-wallet-standard/core)"
245
+ : "";
246
+ return {
247
+ ok: false,
248
+ message: `npm install failed: ${(e.message ?? "unknown error").split("\n")[0]}${hint}`,
249
+ };
250
+ }
251
+
252
+ if (!(await isOwsAvailable())) {
253
+ return {
254
+ ok: false,
255
+ message: "OWS installed but the module could not be loaded. Restart Claude Code (or whichever MCP host) and retry.",
256
+ needsRestart: true,
257
+ };
258
+ }
259
+
260
+ return { ok: true, message: "OWS installed and ready." };
261
+ }
262
+
172
263
  /**
173
264
  * Build a viem-compatible `LocalAccount` backed by an OWS wallet.
174
265
  *
@@ -24,6 +24,8 @@ import {
24
24
  importKeyToOws,
25
25
  listOwsWallets,
26
26
  listOwsWalletsByChain,
27
+ installOws,
28
+ platformSupportsOws,
27
29
  } from "../core/ows-adapter.js";
28
30
  import { ensureConsumerPrincipal, getConsumerPrincipal } from "../core/principal.js";
29
31
 
@@ -97,6 +99,17 @@ export function registerWalletTools(server: McpServer): void {
97
99
  lines.push("", `Consumer principal: ${consumerPrincipal}`);
98
100
  }
99
101
 
102
+ const plaintextWallets = wallets.filter((w) => w.keyType !== "ows");
103
+ if (plaintextWallets.length > 0) {
104
+ const owsAvailable = await isOwsAvailable();
105
+ if (!owsAvailable && platformSupportsOws()) {
106
+ lines.push(
107
+ "",
108
+ `⚠ ${plaintextWallets.length} wallet(s) stored in plaintext. Run wallet_setup({ action: "enable-ows" }) to upgrade to encrypted storage.`,
109
+ );
110
+ }
111
+ }
112
+
100
113
  return text(lines.join("\n"));
101
114
  },
102
115
  );
@@ -104,11 +117,11 @@ export function registerWalletTools(server: McpServer): void {
104
117
  // ── wallet_setup ────────────────────────────────────────────────
105
118
  server.tool(
106
119
  "wallet_setup",
107
- "Set up or manage a payment wallet. 'create' makes a new encrypted crypto wallet (OWS); 'import' takes an existing private key. Tempo/Base share one EVM key — a single wallet covers both. Solana uses a separate ed25519 key. For crypto wallet deletion or key rotation, direct users to edit ~/.agentwonderland/config.json or ~/.ows/ manually; never handle key material programmatically.",
120
+ "Set up or manage a payment wallet. 'create' makes a new crypto wallet (encrypted via OWS if available, otherwise plaintext — run 'enable-ows' to upgrade). 'import' takes an existing private key. 'enable-ows' installs the Open Wallet Standard native module for encrypted at-rest storage. Tempo/Base share one EVM key; Solana uses a separate ed25519 key. NEVER delete or rotate keys programmatically; direct users to edit ~/.agentwonderland/config.json or ~/.ows/ manually.",
108
121
  {
109
122
  action: z
110
- .enum(["create", "import", "add-card", "remove-card"])
111
- .describe("'create' a crypto wallet (recommended), 'import' an existing key, 'add-card'/'remove-card' for credit card (card-backed MPP availability depends on Stripe SPT)"),
123
+ .enum(["create", "import", "add-card", "remove-card", "enable-ows"])
124
+ .describe("'create' a wallet, 'import' an existing key, 'enable-ows' to install encrypted key storage, 'add-card'/'remove-card' for credit card (may be disabled depending on Stripe SPT availability)"),
112
125
  name: z
113
126
  .string()
114
127
  .optional()
@@ -181,6 +194,34 @@ export function registerWalletTools(server: McpServer): void {
181
194
  return text(`Removed ${existing.brand} ****${existing.last4}. Card disconnected from Agent Wonderland.`);
182
195
  }
183
196
 
197
+ // ── Install OWS for encrypted key storage ────────────────
198
+ if (action === "enable-ows") {
199
+ if (await isOwsAvailable()) {
200
+ return text("OWS is already installed — your crypto wallets are stored with AES-256-GCM encryption at rest.");
201
+ }
202
+ if (!platformSupportsOws()) {
203
+ return text(
204
+ `Your platform (${process.platform}-${process.arch}) does not have a prebuilt OWS binary.\n` +
205
+ "Plaintext storage will remain in effect. To install from source you'd need Node build tools (python3, make, node-gyp).",
206
+ );
207
+ }
208
+ const result = await installOws();
209
+ if (result.ok) {
210
+ const plaintextWallets = getWallets().filter((w) => w.keyType !== "ows");
211
+ const migrationHint = plaintextWallets.length > 0
212
+ ? "\n\nExisting plaintext wallets are NOT auto-migrated. To move them to encrypted storage, re-import each via wallet_setup({ action: \"import\", key: \"<hex>\" }) after OWS is active, then delete the plaintext copy from ~/.agentwonderland/config.json."
213
+ : "";
214
+ return text(
215
+ `${result.message}\n\n` +
216
+ `New wallets created via wallet_setup({ action: "create" }) will now use encrypted storage.${migrationHint}`,
217
+ );
218
+ }
219
+ return text(
220
+ `Could not install OWS: ${result.message}\n\n` +
221
+ "Plaintext storage still works. Try again later or install manually: npm install -g @open-wallet-standard/core",
222
+ );
223
+ }
224
+
184
225
  // ── Crypto wallet setup ──────────────────────────────────
185
226
  if (action === "import" && !key) {
186
227
  return text(
@@ -261,17 +302,19 @@ export function registerWalletTools(server: McpServer): void {
261
302
  label: walletName,
262
303
  });
263
304
  const principal = await ensureConsumerPrincipal();
305
+ const owsNudge = platformSupportsOws()
306
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
307
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
264
308
  return text(
265
309
  [
266
- "Wallet created [plaintext — install OWS for encrypted storage]:",
310
+ "Wallet created:",
267
311
  ` Address: ${kp.publicKey.toBase58()}`,
268
312
  ` Name: ${walletName}`,
269
313
  ` Chains: solana`,
270
314
  ` Consumer principal: ${principal}`,
271
315
  "",
272
316
  "Fund this address with USDC on Solana to start using agents.",
273
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
274
- ].join("\n"),
317
+ ].join("\n") + owsNudge,
275
318
  );
276
319
  }
277
320
  const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
@@ -286,17 +329,19 @@ export function registerWalletTools(server: McpServer): void {
286
329
  label: walletName,
287
330
  });
288
331
  const principal = await ensureConsumerPrincipal();
332
+ const owsNudge = platformSupportsOws()
333
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
334
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
289
335
  return text(
290
336
  [
291
- "Wallet created [plaintext — install OWS for encrypted storage]:",
337
+ "Wallet created:",
292
338
  ` Address: ${account.address}`,
293
339
  ` Name: ${walletName}`,
294
340
  ` Chains: tempo, base`,
295
341
  ` Consumer principal: ${principal}`,
296
342
  "",
297
343
  `Fund this address with USDC on Tempo or Base to start using agents.`,
298
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
299
- ].join("\n"),
344
+ ].join("\n") + owsNudge,
300
345
  );
301
346
  }
302
347
 
@@ -374,16 +419,17 @@ export function registerWalletTools(server: McpServer): void {
374
419
  label: walletName,
375
420
  });
376
421
  const principal = await ensureConsumerPrincipal();
422
+ const owsNudge = platformSupportsOws()
423
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
424
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
377
425
  return text(
378
426
  [
379
- "Key imported [plaintext — install OWS for encrypted storage]:",
427
+ "Key imported:",
380
428
  ` Address: ${kp.publicKey.toBase58()}`,
381
429
  ` Name: ${walletName}`,
382
430
  ` Chains: solana`,
383
431
  ` Consumer principal: ${principal}`,
384
- "",
385
- "For encrypted storage, install OWS: npm install -g @open-wallet-standard/core",
386
- ].join("\n"),
432
+ ].join("\n") + owsNudge,
387
433
  );
388
434
  } catch (err) {
389
435
  return text(
@@ -412,16 +458,17 @@ export function registerWalletTools(server: McpServer): void {
412
458
  });
413
459
  const principal = await ensureConsumerPrincipal();
414
460
 
461
+ const owsNudge = platformSupportsOws()
462
+ ? "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. Run wallet_setup({ action: \"enable-ows\" }) to install encrypted at-rest storage — takes ~30s."
463
+ : "\n\n⚠ Key stored in plaintext at ~/.agentwonderland/config.json. OWS encrypted storage isn't available for your platform.";
415
464
  return text(
416
465
  [
417
- `Key imported [plaintext] \u2014 OWS not available for encrypted storage.`,
466
+ `Key imported:`,
418
467
  ` Address: ${account.address}`,
419
468
  ` Name: ${walletName}`,
420
469
  ` Chains: ${selectedChains.join(", ")}`,
421
470
  ` Consumer principal: ${principal}`,
422
- "",
423
- "Install OWS for encrypted storage: npm install -g @open-wallet-standard/core",
424
- ].join("\n"),
471
+ ].join("\n") + owsNudge,
425
472
  );
426
473
  } catch {
427
474
  return text("Error: Invalid private key format.");