@elisym/mcp 0.24.0 → 0.25.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.
package/README.md CHANGED
@@ -112,12 +112,12 @@ The bootstrap step is unchanged - the wizard collects the passphrase interactive
112
112
  | `ELISYM_AGENT` | Load agent from `~/.elisym/<name>/` (or a project-local `.elisym/<name>/`) |
113
113
  | `ELISYM_NOSTR_SECRET` | Nostr secret key (hex or nsec) for ephemeral mode |
114
114
  | `ELISYM_AGENT_NAME` | Agent display name (default: mcp-agent) |
115
- | `ELISYM_NETWORK` | Solana network for ephemeral/auto-created identities: `devnet` (default) or `mainnet`. It cannot override a disk-loaded agent - an agent's network is fixed at creation, and a conflicting value fails startup |
115
+ | `ELISYM_NETWORK` | Solana network for ephemeral/auto-created identities: `mainnet` (default) or `devnet`. It cannot override a disk-loaded agent - an agent's network is fixed at creation, and a conflicting value fails startup |
116
116
  | `ELISYM_PASSPHRASE` | Passphrase for encrypted agent configs (optional) |
117
117
  | `ELISYM_ALLOW_WITHDRAWAL` | Set to `1` to override per-agent `security.withdrawals_enabled` flag (CI use) |
118
118
  | `ELISYM_ALLOW_AGENT_SWITCH` | Set to `1` to override per-agent `security.agent_switch_enabled` flag |
119
119
 
120
- The RPC endpoint is always the public one for each agent's network (`api.devnet.solana.com` / `api.mainnet-beta.solana.com`). The MCP server deliberately does **not** honor `SOLANA_RPC_URL`: one process can host agents on both networks, and a process-wide override could point a devnet agent's payment path at mainnet. Creating a mainnet agent: `npx @elisym/mcp init <name> --network mainnet` (or the `create_agent` tool's `network` parameter); the network is fixed at creation, and `switch_agent` to a mainnet-bound agent is how a session changes network.
120
+ The RPC endpoint is always the public one for each agent's network (`api.devnet.solana.com` / `api.mainnet-beta.solana.com`). The MCP server deliberately does **not** honor `SOLANA_RPC_URL`: one process can host agents on both networks, and a process-wide override could point a devnet agent's payment path at mainnet. New agents are mainnet by default and move real funds. Creating a devnet agent to experiment with: `npx @elisym/mcp init <name> --network devnet` (or the `create_agent` tool's `network` parameter); the network is fixed at creation, and `switch_agent` to an agent on the other network is how a session changes network. An agent created before this default flipped keeps the network its YAML records - an upgrade never re-points an existing agent at mainnet.
121
121
 
122
122
  ## Usage Examples
123
123
 
package/dist/index.js CHANGED
@@ -22,81 +22,7 @@ import { fileURLToPath } from 'node:url';
22
22
  import { getTransferSolInstruction } from '@solana-program/system';
23
23
  import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, getCreateAssociatedTokenIdempotentInstruction, ASSOCIATED_TOKEN_PROGRAM_ADDRESS, getTransferCheckedInstruction } from '@solana-program/token';
24
24
 
25
- function coerceNetwork(raw, name) {
26
- if (raw === void 0 || raw === "devnet") {
27
- return "devnet";
28
- }
29
- if (raw === "mainnet") {
30
- return "mainnet";
31
- }
32
- throw new Error(
33
- `Agent "${name}" has unsupported network "${raw}". Expected "devnet" or "mainnet".`
34
- );
35
- }
36
- async function loadAgentConfig(name, passphrase) {
37
- validateAgentName(name);
38
- const loaded = await loadAgent(name, process.cwd(), passphrase);
39
- const solPayment = loaded.yaml.payments.find((entry) => entry.chain === "solana");
40
- const network = coerceNetwork(solPayment?.network, name);
41
- return {
42
- nostrSecretKey: loaded.secrets.nostr_secret_key,
43
- solanaSecretKey: loaded.secrets.solana_secret_key,
44
- relays: loaded.yaml.relays.length > 0 ? loaded.yaml.relays : void 0,
45
- network,
46
- payments: loaded.yaml.payments.length > 0 ? loaded.yaml.payments.map((payment2) => ({
47
- chain: payment2.chain,
48
- network: payment2.network,
49
- address: payment2.address
50
- })) : void 0,
51
- security: {
52
- withdrawals_enabled: loaded.yaml.security.withdrawals_enabled,
53
- agent_switch_enabled: loaded.yaml.security.agent_switch_enabled
54
- },
55
- encrypted: loaded.encrypted
56
- };
57
- }
58
- async function saveAgentConfig(name, input) {
59
- validateAgentName(name);
60
- const created = await createAgentDir({ target: "home", name, cwd: process.cwd() });
61
- const network = input.network ?? "devnet";
62
- try {
63
- await writeFile(created.paths.yaml, "", { flag: "wx", mode: 420 });
64
- } catch (error) {
65
- if (error instanceof Error && "code" in error && error.code === "EEXIST") {
66
- throw new Error(`Agent "${name}" already exists.`);
67
- }
68
- throw error;
69
- }
70
- await writeYamlInitial(created.dir, {
71
- display_name: void 0,
72
- description: input.description,
73
- picture: void 0,
74
- banner: void 0,
75
- relays: input.relays,
76
- payments: input.solanaAddress ? [{ chain: "solana", network, address: input.solanaAddress }] : [],
77
- llm: void 0,
78
- security: input.security ?? {}
79
- });
80
- await writeExampleSkillTemplate(created.dir);
81
- await writeSecrets(
82
- created.dir,
83
- {
84
- nostr_secret_key: input.nostrSecretKey,
85
- solana_secret_key: input.solanaSecretKey
86
- },
87
- input.passphrase
88
- );
89
- }
90
- async function updateAgentSecurity(name, patch, passphrase) {
91
- const loaded = await loadAgent(name, process.cwd(), passphrase);
92
- const merged = { ...loaded.yaml.security, ...patch };
93
- await writeYaml(loaded.dir, { ...loaded.yaml, security: merged });
94
- return merged;
95
- }
96
- async function listAgentNames() {
97
- const agents = await listAgents(process.cwd());
98
- return agents.map((agent) => agent.name);
99
- }
25
+ var DEFAULT_NETWORK = "mainnet";
100
26
  function rpcUrlFor(network) {
101
27
  return network === "mainnet" ? "https://api.mainnet-beta.solana.com" : "https://api.devnet.solana.com";
102
28
  }
@@ -309,6 +235,83 @@ function takeSpendWarnings(ctx, asset) {
309
235
  ctx.sessionSpendWarnings.set(key, fired);
310
236
  return lines;
311
237
  }
238
+
239
+ // src/config.ts
240
+ function coerceNetwork(raw, name) {
241
+ if (raw === void 0 || raw === "devnet") {
242
+ return "devnet";
243
+ }
244
+ if (raw === "mainnet") {
245
+ return "mainnet";
246
+ }
247
+ throw new Error(
248
+ `Agent "${name}" has unsupported network "${raw}". Expected "devnet" or "mainnet".`
249
+ );
250
+ }
251
+ async function loadAgentConfig(name, passphrase) {
252
+ validateAgentName(name);
253
+ const loaded = await loadAgent(name, process.cwd(), passphrase);
254
+ const solPayment = loaded.yaml.payments.find((entry) => entry.chain === "solana");
255
+ const network = coerceNetwork(solPayment?.network, name);
256
+ return {
257
+ nostrSecretKey: loaded.secrets.nostr_secret_key,
258
+ solanaSecretKey: loaded.secrets.solana_secret_key,
259
+ relays: loaded.yaml.relays.length > 0 ? loaded.yaml.relays : void 0,
260
+ network,
261
+ payments: loaded.yaml.payments.length > 0 ? loaded.yaml.payments.map((payment2) => ({
262
+ chain: payment2.chain,
263
+ network: payment2.network,
264
+ address: payment2.address
265
+ })) : void 0,
266
+ security: {
267
+ withdrawals_enabled: loaded.yaml.security.withdrawals_enabled,
268
+ agent_switch_enabled: loaded.yaml.security.agent_switch_enabled
269
+ },
270
+ encrypted: loaded.encrypted
271
+ };
272
+ }
273
+ async function saveAgentConfig(name, input) {
274
+ validateAgentName(name);
275
+ const created = await createAgentDir({ target: "home", name, cwd: process.cwd() });
276
+ const network = input.network ?? DEFAULT_NETWORK;
277
+ try {
278
+ await writeFile(created.paths.yaml, "", { flag: "wx", mode: 420 });
279
+ } catch (error) {
280
+ if (error instanceof Error && "code" in error && error.code === "EEXIST") {
281
+ throw new Error(`Agent "${name}" already exists.`);
282
+ }
283
+ throw error;
284
+ }
285
+ await writeYamlInitial(created.dir, {
286
+ display_name: void 0,
287
+ description: input.description,
288
+ picture: void 0,
289
+ banner: void 0,
290
+ relays: input.relays,
291
+ payments: input.solanaAddress ? [{ chain: "solana", network, address: input.solanaAddress }] : [],
292
+ llm: void 0,
293
+ security: input.security ?? {}
294
+ });
295
+ await writeExampleSkillTemplate(created.dir);
296
+ await writeSecrets(
297
+ created.dir,
298
+ {
299
+ nostr_secret_key: input.nostrSecretKey,
300
+ solana_secret_key: input.solanaSecretKey
301
+ },
302
+ input.passphrase
303
+ );
304
+ }
305
+ async function updateAgentSecurity(name, patch, passphrase) {
306
+ const loaded = await loadAgent(name, process.cwd(), passphrase);
307
+ const merged = { ...loaded.yaml.security, ...patch };
308
+ await writeYaml(loaded.dir, { ...loaded.yaml, security: merged });
309
+ return merged;
310
+ }
311
+ async function listAgentNames() {
312
+ const agents = await listAgents(process.cwd());
313
+ return agents.map((agent) => agent.name);
314
+ }
312
315
  async function writeFileAtomic(path, content, mode = 384) {
313
316
  const tmpPath = `${path}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
314
317
  try {
@@ -1261,8 +1264,8 @@ var CreateAgentSchema = z.object({
1261
1264
  // customer-mode in 0.1.x and never publishes a NIP-89 capability card,
1262
1265
  // so an advertised capability list would be misleading. Provider-mode
1263
1266
  // (0.2.0) will reintroduce this field.
1264
- network: z.enum(["devnet", "mainnet"]).default("devnet").describe(
1265
- "Solana network this agent is bound to. FIXED AT CREATION: an agent can never change networks - switching networks means creating (or switch_agent-ing to) another agent bound to the other network. Default devnet; mainnet payments move real funds."
1267
+ network: z.enum(["devnet", "mainnet"]).default(DEFAULT_NETWORK).describe(
1268
+ `Solana network this agent is bound to. FIXED AT CREATION: an agent can never change networks - switching networks means creating (or switch_agent-ing to) another agent bound to the other network. Defaults to ${DEFAULT_NETWORK}, where payments move REAL funds; pass "devnet" for an agent to experiment with.`
1266
1269
  ),
1267
1270
  passphrase: z.string().optional().describe("Optional passphrase; if set, secret keys are encrypted at rest."),
1268
1271
  activate: z.boolean().default(true)
@@ -7205,7 +7208,7 @@ program.action(
7205
7208
  }
7206
7209
  const client = new ElisymClient({ relays: RELAYS });
7207
7210
  const name = process.env.ELISYM_AGENT_NAME ?? "mcp-agent";
7208
- const network = envNetwork ?? "devnet";
7211
+ const network = envNetwork ?? DEFAULT_NETWORK;
7209
7212
  ctx.register({ client, identity, name, network, security: {} });
7210
7213
  console.error(`Ephemeral agent: ${name} (${network})`);
7211
7214
  } else {
@@ -7225,7 +7228,7 @@ program.action(
7225
7228
  } else {
7226
7229
  const identity = ElisymIdentity.generate();
7227
7230
  const client = new ElisymClient({ relays: RELAYS });
7228
- const network = envNetwork ?? "devnet";
7231
+ const network = envNetwork ?? DEFAULT_NETWORK;
7229
7232
  ctx.register({ client, identity, name: "mcp-agent", network, security: {} });
7230
7233
  console.error(`Created ephemeral agent (no persistent identity, ${network}).`);
7231
7234
  }
@@ -7235,8 +7238,8 @@ program.action(
7235
7238
  );
7236
7239
  program.command("init [name]").description("Create a new agent identity").option("-d, --description <desc>", "Agent description", "Elisym MCP agent").option(
7237
7240
  "-n, --network <network>",
7238
- "Solana network (devnet or mainnet). Fixed at creation: to change networks later, create a new agent. Mainnet payments move real funds.",
7239
- "devnet"
7241
+ `Solana network (devnet or mainnet). Fixed at creation: to change networks later, create a new agent. Defaults to ${DEFAULT_NETWORK}; mainnet payments move real funds.`,
7242
+ DEFAULT_NETWORK
7240
7243
  ).option("--install", "Also install into MCP clients").option(
7241
7244
  "--passphrase <value>",
7242
7245
  'Passphrase to encrypt secret keys at rest. Empty string ("") skips encryption. Also reads ELISYM_PASSPHRASE env var. When neither is provided, prompts interactively.'
@@ -7262,7 +7265,7 @@ program.command("init [name]").description("Create a new agent identity").option
7262
7265
  name: "network",
7263
7266
  message: "Solana network (fixed at creation - create a new agent to change it):",
7264
7267
  choices: ["devnet", "mainnet"],
7265
- default: "devnet"
7268
+ default: DEFAULT_NETWORK
7266
7269
  }
7267
7270
  ]);
7268
7271
  name = answers.name;