@elisym/mcp 0.1.5 → 0.1.7
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 +3 -0
- package/dist/index.js +228 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,9 @@ npx @elisym/mcp install --agent <agent-name>
|
|
|
20
20
|
# List detected MCP clients
|
|
21
21
|
npx @elisym/mcp install --list
|
|
22
22
|
|
|
23
|
+
# Refresh the version pin in installed clients (preserves agent + env)
|
|
24
|
+
npx @elisym/mcp update
|
|
25
|
+
|
|
23
26
|
# Remove from MCP clients
|
|
24
27
|
npx @elisym/mcp uninstall
|
|
25
28
|
|
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ async function saveAgentConfig(name, config) {
|
|
|
91
91
|
description: config.description
|
|
92
92
|
},
|
|
93
93
|
relays: config.relays,
|
|
94
|
-
capabilities: config.capabilities,
|
|
94
|
+
capabilities: config.capabilities ?? [],
|
|
95
95
|
...config.solanaAddress && {
|
|
96
96
|
payments: [
|
|
97
97
|
{
|
|
@@ -319,6 +319,35 @@ function payment() {
|
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
// src/install.ts
|
|
322
|
+
function elisymPackageArgs() {
|
|
323
|
+
return ["-y", `@elisym/mcp@~${PACKAGE_VERSION}`];
|
|
324
|
+
}
|
|
325
|
+
function validateClientName(name) {
|
|
326
|
+
if (name === void 0) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (!CLIENTS.some((c) => c.name === name)) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
`Unknown client "${name}". Known clients: ${CLIENTS.map((c) => c.name).join(", ")}`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function safeRewriteJson(path, expectedRaw, newConfig) {
|
|
336
|
+
let recheck;
|
|
337
|
+
try {
|
|
338
|
+
recheck = await readFile(path, "utf-8");
|
|
339
|
+
} catch (err) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
`${path} disappeared between read and write: ${err.message}. Re-run after the file is restored.`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (recheck !== expectedRaw) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
`${path} was modified by another process during update. Close the MCP client and re-run.`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
await writeJsonAtomic(path, newConfig);
|
|
350
|
+
}
|
|
322
351
|
var CLIENTS = [
|
|
323
352
|
{
|
|
324
353
|
name: "claude-desktop",
|
|
@@ -334,6 +363,15 @@ var CLIENTS = [
|
|
|
334
363
|
}
|
|
335
364
|
}
|
|
336
365
|
},
|
|
366
|
+
{
|
|
367
|
+
name: "claude-code",
|
|
368
|
+
// Claude Code CLI keeps user-scope MCP servers under `mcpServers` at the top
|
|
369
|
+
// level of `~/.claude.json`. Project-scope (`.mcp.json` in cwd) and local-scope
|
|
370
|
+
// (`projects.<path>.mcpServers` inside the same file) are deliberately not
|
|
371
|
+
// touched here - this installer only writes user scope so the server is
|
|
372
|
+
// available across all projects.
|
|
373
|
+
configPath: () => join(homedir(), ".claude.json")
|
|
374
|
+
},
|
|
337
375
|
{
|
|
338
376
|
name: "cursor",
|
|
339
377
|
configPath: () => join(homedir(), ".cursor/mcp.json")
|
|
@@ -352,7 +390,7 @@ var CLIENTS = [
|
|
|
352
390
|
function buildServerEntry(agentName, env) {
|
|
353
391
|
const entry = {
|
|
354
392
|
command: "npx",
|
|
355
|
-
args:
|
|
393
|
+
args: elisymPackageArgs()
|
|
356
394
|
};
|
|
357
395
|
const mergedEnv = { ...env };
|
|
358
396
|
if (agentName) {
|
|
@@ -364,6 +402,7 @@ function buildServerEntry(agentName, env) {
|
|
|
364
402
|
return entry;
|
|
365
403
|
}
|
|
366
404
|
async function runInstall(options) {
|
|
405
|
+
validateClientName(options.client);
|
|
367
406
|
if (options.agent) {
|
|
368
407
|
validateAgentName(options.agent);
|
|
369
408
|
}
|
|
@@ -393,7 +432,12 @@ async function runInstall(options) {
|
|
|
393
432
|
console.log("No MCP clients found to install into.");
|
|
394
433
|
}
|
|
395
434
|
}
|
|
396
|
-
async function
|
|
435
|
+
async function runUpdate(options) {
|
|
436
|
+
validateClientName(options.client);
|
|
437
|
+
if (options.agent) {
|
|
438
|
+
validateAgentName(options.agent);
|
|
439
|
+
}
|
|
440
|
+
let updated = 0;
|
|
397
441
|
for (const client of CLIENTS) {
|
|
398
442
|
if (options.client && client.name !== options.client) {
|
|
399
443
|
continue;
|
|
@@ -402,15 +446,105 @@ async function runUninstall(options) {
|
|
|
402
446
|
if (!path) {
|
|
403
447
|
continue;
|
|
404
448
|
}
|
|
449
|
+
let raw;
|
|
405
450
|
try {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (
|
|
409
|
-
|
|
410
|
-
await writeJsonAtomic(path, config);
|
|
411
|
-
console.log(`Removed from ${client.name}: ${path}`);
|
|
451
|
+
raw = await readFile(path, "utf-8");
|
|
452
|
+
} catch (err) {
|
|
453
|
+
if (err.code !== "ENOENT") {
|
|
454
|
+
console.log(`Skipped ${client.name}: ${err.message}`);
|
|
412
455
|
}
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
let config;
|
|
459
|
+
try {
|
|
460
|
+
config = JSON.parse(raw);
|
|
413
461
|
} catch {
|
|
462
|
+
console.log(`Warning: ${path} is not valid JSON. Skipping update for ${client.name}.`);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const existing = config.mcpServers?.elisym;
|
|
466
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const rawEnv = existing.env;
|
|
470
|
+
const newEnv = rawEnv && typeof rawEnv === "object" && !Array.isArray(rawEnv) ? { ...rawEnv } : {};
|
|
471
|
+
const existingAgentRaw = typeof newEnv.ELISYM_AGENT === "string" ? newEnv.ELISYM_AGENT : void 0;
|
|
472
|
+
if (existingAgentRaw !== void 0 && options.agent === void 0) {
|
|
473
|
+
try {
|
|
474
|
+
validateAgentName(existingAgentRaw);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
console.log(
|
|
477
|
+
`Skipped ${client.name}: existing ELISYM_AGENT in ${path} is invalid (${err.message}). Re-run with --agent <name> to overwrite.`
|
|
478
|
+
);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (options.agent !== void 0) {
|
|
483
|
+
newEnv.ELISYM_AGENT = options.agent;
|
|
484
|
+
}
|
|
485
|
+
const entry = existing;
|
|
486
|
+
const newArgs = elisymPackageArgs();
|
|
487
|
+
if (Array.isArray(entry.args)) {
|
|
488
|
+
const idx = entry.args.findIndex(
|
|
489
|
+
(a) => typeof a === "string" && a.startsWith("@elisym/mcp@")
|
|
490
|
+
);
|
|
491
|
+
if (idx >= 0) {
|
|
492
|
+
entry.args[idx] = newArgs[1];
|
|
493
|
+
} else {
|
|
494
|
+
entry.args = newArgs;
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
entry.args = newArgs;
|
|
498
|
+
}
|
|
499
|
+
if (Object.keys(newEnv).length > 0) {
|
|
500
|
+
entry.env = newEnv;
|
|
501
|
+
} else {
|
|
502
|
+
delete entry.env;
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
await safeRewriteJson(path, raw, config);
|
|
506
|
+
} catch (err) {
|
|
507
|
+
console.log(`Skipped ${client.name}: ${err.message}`);
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
console.log(`Updated ${client.name}: ${path} -> @elisym/mcp@~${PACKAGE_VERSION}`);
|
|
511
|
+
updated++;
|
|
512
|
+
}
|
|
513
|
+
if (updated === 0) {
|
|
514
|
+
console.log("No existing elisym MCP installs found to update.");
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
async function runUninstall(options) {
|
|
518
|
+
validateClientName(options.client);
|
|
519
|
+
for (const client of CLIENTS) {
|
|
520
|
+
if (options.client && client.name !== options.client) {
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const path = client.configPath();
|
|
524
|
+
if (!path) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
let raw;
|
|
528
|
+
try {
|
|
529
|
+
raw = await readFile(path, "utf-8");
|
|
530
|
+
} catch {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
let config;
|
|
534
|
+
try {
|
|
535
|
+
config = JSON.parse(raw);
|
|
536
|
+
} catch {
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
if (!config.mcpServers?.elisym) {
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
delete config.mcpServers.elisym;
|
|
543
|
+
try {
|
|
544
|
+
await safeRewriteJson(path, raw, config);
|
|
545
|
+
console.log(`Removed from ${client.name}: ${path}`);
|
|
546
|
+
} catch (err) {
|
|
547
|
+
console.log(`Skipped ${client.name}: ${err.message}`);
|
|
414
548
|
}
|
|
415
549
|
}
|
|
416
550
|
}
|
|
@@ -435,18 +569,21 @@ async function writeJsonAtomic(path, data) {
|
|
|
435
569
|
await writeFileAtomic(path, JSON.stringify(data, null, 2), 384);
|
|
436
570
|
}
|
|
437
571
|
async function installToConfig(path, entry) {
|
|
438
|
-
let config;
|
|
439
572
|
let raw;
|
|
440
573
|
try {
|
|
441
574
|
raw = await readFile(path, "utf-8");
|
|
575
|
+
} catch (err) {
|
|
576
|
+
if (err.code !== "ENOENT") {
|
|
577
|
+
throw err;
|
|
578
|
+
}
|
|
579
|
+
await writeJsonAtomic(path, { mcpServers: { elisym: entry } });
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
let config;
|
|
583
|
+
try {
|
|
442
584
|
config = JSON.parse(raw);
|
|
443
585
|
} catch {
|
|
444
|
-
|
|
445
|
-
console.error(
|
|
446
|
-
`Warning: ${path} is not valid JSON. A backup was saved to ${path}.elisym-backup. Other MCP server entries may have been lost - restore from backup if needed.`
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
config = {};
|
|
586
|
+
throw new Error(`${path} is not valid JSON. Fix the file manually and re-run install.`);
|
|
450
587
|
}
|
|
451
588
|
if (!config.mcpServers) {
|
|
452
589
|
config.mcpServers = {};
|
|
@@ -454,14 +591,8 @@ async function installToConfig(path, entry) {
|
|
|
454
591
|
if (config.mcpServers.elisym) {
|
|
455
592
|
return false;
|
|
456
593
|
}
|
|
457
|
-
if (raw) {
|
|
458
|
-
try {
|
|
459
|
-
await writeFile(`${path}.elisym-backup`, raw, { mode: 384 });
|
|
460
|
-
} catch {
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
594
|
config.mcpServers.elisym = entry;
|
|
464
|
-
await
|
|
595
|
+
await safeRewriteJson(path, raw, config);
|
|
465
596
|
return true;
|
|
466
597
|
}
|
|
467
598
|
|
|
@@ -480,7 +611,10 @@ function errorResult(text) {
|
|
|
480
611
|
var CreateAgentSchema = z.object({
|
|
481
612
|
name: z.string().min(1).max(64),
|
|
482
613
|
description: z.string().default("Elisym MCP agent"),
|
|
483
|
-
capabilities:
|
|
614
|
+
// capabilities are intentionally not exposed: the MCP server runs in
|
|
615
|
+
// customer-mode in 0.1.x and never publishes a NIP-89 capability card,
|
|
616
|
+
// so an advertised capability list would be misleading. Provider-mode
|
|
617
|
+
// (0.2.0) will reintroduce this field.
|
|
484
618
|
network: z.enum(["devnet", "mainnet"]).default("devnet"),
|
|
485
619
|
passphrase: z.string().optional().describe("Optional passphrase; if set, secret keys are encrypted at rest."),
|
|
486
620
|
activate: z.boolean().default(true)
|
|
@@ -564,11 +698,9 @@ var agentTools = [
|
|
|
564
698
|
const solanaKeypair = Keypair.generate();
|
|
565
699
|
const nostrSecretHex = Buffer.from(nostrSecretKey).toString("hex");
|
|
566
700
|
const solanaSecretBase58 = bs58.encode(solanaKeypair.secretKey);
|
|
567
|
-
const capabilities = input.capabilities.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((tag) => ({ name: tag, description: tag, tags: [tag], price: 0 }));
|
|
568
701
|
await saveAgentConfig(input.name, {
|
|
569
702
|
name: input.name,
|
|
570
703
|
description: input.description,
|
|
571
|
-
capabilities,
|
|
572
704
|
relays: [...RELAYS],
|
|
573
705
|
nostrSecretKey: nostrSecretHex,
|
|
574
706
|
solanaSecretKey: solanaSecretBase58,
|
|
@@ -800,8 +932,13 @@ function normalizeConfusables(text) {
|
|
|
800
932
|
return text.normalize("NFKC").replace(CONFUSABLE_RE, (ch) => CONFUSABLE_MAP[ch] ?? ch);
|
|
801
933
|
}
|
|
802
934
|
var INJECTION_PATTERNS = [
|
|
803
|
-
// Role hijacking
|
|
804
|
-
|
|
935
|
+
// Role hijacking — agents legitimately describe themselves with "act as" /
|
|
936
|
+
// "you are" in their public cards, so this is noisy in structured contexts.
|
|
937
|
+
{
|
|
938
|
+
category: "role_hijack",
|
|
939
|
+
pattern: /\b(?:you are|act as|pretend to be|roleplay as)\b/i,
|
|
940
|
+
noisy: true
|
|
941
|
+
},
|
|
805
942
|
// Instruction override
|
|
806
943
|
{
|
|
807
944
|
category: "instruction_override",
|
|
@@ -819,16 +956,35 @@ var INJECTION_PATTERNS = [
|
|
|
819
956
|
},
|
|
820
957
|
// Delimiter injection
|
|
821
958
|
{ category: "delimiter_injection", pattern: /<\/system>|\[\/INST\]|```system|<\|im_end\|>/i },
|
|
822
|
-
// Data exfiltration
|
|
823
|
-
|
|
959
|
+
// Data exfiltration. Require a composite term ("secret key", "api key") or a strong
|
|
960
|
+
// single noun ("password", "credential", "seed phrase"). The previous version matched
|
|
961
|
+
// the bare word "key", which produces false positives on benign phrases like
|
|
962
|
+
// "send a link, get the key points" — common in legitimate agent descriptions.
|
|
963
|
+
// Cap the gap at 40 chars within the same clause (no sentence terminators) so the
|
|
964
|
+
// verb and noun must actually relate to each other. Composite-term separators are
|
|
965
|
+
// [\s_-]? so variants like `private-key`, `secret_key`, `seed-phrase` are caught.
|
|
966
|
+
// Marked `noisy` because even after tightening, NL verb+noun phrases remain a
|
|
967
|
+
// common source of FP on free-text agent descriptions.
|
|
968
|
+
{
|
|
969
|
+
category: "data_exfil",
|
|
970
|
+
pattern: /\b(?:send|post|exfiltrate|leak)\b[^.!?\n]{0,40}\b(?:secret[\s_-]?key|api[\s_-]?key|private[\s_-]?key|password|credential|auth[\s_-]?token|seed[\s_-]?phrase|mnemonic)\b/i,
|
|
971
|
+
noisy: true
|
|
972
|
+
},
|
|
824
973
|
// Payment manipulation
|
|
825
974
|
{ category: "payment_manipulation", pattern: /\b(?:change|modify).*?\b(?:recipient|address)\b/i },
|
|
826
975
|
{ category: "payment_manipulation", pattern: /\bsend all funds\b/i },
|
|
827
|
-
// Jailbreak
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
976
|
+
// Jailbreak — "from now on" is a common phrase in changelogs/release notes that
|
|
977
|
+
// an agent could legitimately put in its description, hence noisy.
|
|
978
|
+
{
|
|
979
|
+
category: "jailbreak",
|
|
980
|
+
pattern: /\b(?:DAN mode|developer mode enabled|from now on)\b/i,
|
|
981
|
+
noisy: true
|
|
982
|
+
},
|
|
983
|
+
// Urgency — agents may put "IMPORTANT: rate limited to N req/s" in their card,
|
|
984
|
+
// so the line-anchored prefix is noisy in structured contexts.
|
|
985
|
+
{ category: "urgency", pattern: /^(?:IMPORTANT|CRITICAL|URGENT|SYSTEM):/m, noisy: true }
|
|
831
986
|
];
|
|
987
|
+
var STRICT_INJECTION_PATTERNS = INJECTION_PATTERNS.filter((p) => !p.noisy);
|
|
832
988
|
function stripDangerousUnicode(text) {
|
|
833
989
|
return text.replace(
|
|
834
990
|
// eslint-disable-next-line no-control-regex
|
|
@@ -842,14 +998,18 @@ function truncateLongLines(text) {
|
|
|
842
998
|
).join("\n");
|
|
843
999
|
}
|
|
844
1000
|
var INJECTION_SCAN_BUDGET = 8e3;
|
|
845
|
-
function detectInjections(text) {
|
|
1001
|
+
function detectInjections(text, includeNoisy) {
|
|
846
1002
|
const normalized = normalizeConfusables(text);
|
|
1003
|
+
const patterns = includeNoisy ? INJECTION_PATTERNS : STRICT_INJECTION_PATTERNS;
|
|
847
1004
|
if (normalized.length <= INJECTION_SCAN_BUDGET) {
|
|
848
|
-
return
|
|
1005
|
+
return patterns.some((p) => p.pattern.test(normalized));
|
|
849
1006
|
}
|
|
850
1007
|
const head = normalized.slice(0, INJECTION_SCAN_BUDGET);
|
|
851
1008
|
const tail = normalized.slice(-INJECTION_SCAN_BUDGET);
|
|
852
|
-
return
|
|
1009
|
+
return patterns.some((p) => p.pattern.test(head) || p.pattern.test(tail));
|
|
1010
|
+
}
|
|
1011
|
+
function scanForInjections(text, mode = "full") {
|
|
1012
|
+
return detectInjections(text, mode === "full");
|
|
853
1013
|
}
|
|
854
1014
|
function isLikelyBase64(s) {
|
|
855
1015
|
if (s.length < 64) {
|
|
@@ -858,12 +1018,13 @@ function isLikelyBase64(s) {
|
|
|
858
1018
|
const base64Chars = s.replace(/[A-Za-z0-9+/=\s]/g, "");
|
|
859
1019
|
return base64Chars.length / s.length < 0.05;
|
|
860
1020
|
}
|
|
861
|
-
function sanitizeUntrusted(input, kind = "text") {
|
|
1021
|
+
function sanitizeUntrusted(input, kind = "text", options) {
|
|
862
1022
|
let text = stripDangerousUnicode(input);
|
|
863
1023
|
text = truncateLongLines(text);
|
|
864
1024
|
text = text.replaceAll(BOUNDARY_BEGIN, "--- [UNTRUSTED MARKER STRIPPED] ---");
|
|
865
1025
|
text = text.replaceAll(BOUNDARY_END, "--- [UNTRUSTED MARKER STRIPPED] ---");
|
|
866
|
-
const
|
|
1026
|
+
const scanned = kind !== "binary" && detectInjections(text, kind === "text");
|
|
1027
|
+
const injectionsDetected = scanned || options?.extraInjectionSignal === true;
|
|
867
1028
|
let wrapped = `${BOUNDARY_BEGIN}
|
|
868
1029
|
${text}
|
|
869
1030
|
${BOUNDARY_END}`;
|
|
@@ -874,14 +1035,14 @@ ${wrapped}`;
|
|
|
874
1035
|
}
|
|
875
1036
|
return { text: wrapped, injectionsDetected };
|
|
876
1037
|
}
|
|
1038
|
+
function sanitizeInner(input) {
|
|
1039
|
+
return truncateLongLines(stripDangerousUnicode(input));
|
|
1040
|
+
}
|
|
877
1041
|
function sanitizeField(input, maxLen) {
|
|
878
1042
|
let text = stripDangerousUnicode(input);
|
|
879
1043
|
if (text.length > maxLen) {
|
|
880
1044
|
text = text.slice(0, maxLen) + "...";
|
|
881
1045
|
}
|
|
882
|
-
if (detectInjections(text)) {
|
|
883
|
-
text = `[SUSPICIOUS] ${text}`;
|
|
884
|
-
}
|
|
885
1046
|
return text;
|
|
886
1047
|
}
|
|
887
1048
|
|
|
@@ -1202,13 +1363,26 @@ var customerTools = [
|
|
|
1202
1363
|
console.error("[mcp:list_my_jobs] queryJobResults failed:", e);
|
|
1203
1364
|
}
|
|
1204
1365
|
}
|
|
1366
|
+
let freetextSuspicious = false;
|
|
1205
1367
|
const results = mine.map((job) => {
|
|
1206
1368
|
const dec = decryptedByRequest.get(job.eventId);
|
|
1207
1369
|
let resultText;
|
|
1208
1370
|
if (dec) {
|
|
1209
|
-
|
|
1371
|
+
if (dec.decryptionFailed) {
|
|
1372
|
+
resultText = "[decryption failed - targeted result not for this agent]";
|
|
1373
|
+
} else {
|
|
1374
|
+
const cleaned = sanitizeInner(dec.content);
|
|
1375
|
+
if (scanForInjections(cleaned, "full")) {
|
|
1376
|
+
freetextSuspicious = true;
|
|
1377
|
+
}
|
|
1378
|
+
resultText = cleaned;
|
|
1379
|
+
}
|
|
1210
1380
|
} else if (job.result) {
|
|
1211
|
-
|
|
1381
|
+
const cleaned = sanitizeInner(job.result);
|
|
1382
|
+
if (scanForInjections(cleaned, "full")) {
|
|
1383
|
+
freetextSuspicious = true;
|
|
1384
|
+
}
|
|
1385
|
+
resultText = cleaned;
|
|
1212
1386
|
}
|
|
1213
1387
|
return {
|
|
1214
1388
|
event_id: job.eventId,
|
|
@@ -1219,10 +1393,11 @@ var customerTools = [
|
|
|
1219
1393
|
result: resultText
|
|
1220
1394
|
};
|
|
1221
1395
|
});
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1396
|
+
const { text: wrapped } = sanitizeUntrusted(JSON.stringify(results, null, 2), "structured", {
|
|
1397
|
+
extraInjectionSignal: freetextSuspicious
|
|
1398
|
+
});
|
|
1399
|
+
return textResult(`Found ${results.length} of your jobs:
|
|
1400
|
+
${wrapped}`);
|
|
1226
1401
|
}
|
|
1227
1402
|
}),
|
|
1228
1403
|
defineTool({
|
|
@@ -2292,7 +2467,7 @@ program.action(async () => {
|
|
|
2292
2467
|
}
|
|
2293
2468
|
await startServer(ctx);
|
|
2294
2469
|
});
|
|
2295
|
-
program.command("init [name]").description("Create a new agent identity").option("-d, --description <desc>", "Agent description", "Elisym MCP agent").option("-
|
|
2470
|
+
program.command("init [name]").description("Create a new agent identity").option("-d, --description <desc>", "Agent description", "Elisym MCP agent").option("-n, --network <network>", "Solana network (devnet|mainnet)", "devnet").option("--install", "Also install into MCP clients").action(async (name, options) => {
|
|
2296
2471
|
const { default: inquirer } = await import('inquirer');
|
|
2297
2472
|
if (!name) {
|
|
2298
2473
|
const answers = await inquirer.prompt([
|
|
@@ -2308,12 +2483,6 @@ program.command("init [name]").description("Create a new agent identity").option
|
|
|
2308
2483
|
message: "Description:",
|
|
2309
2484
|
default: "Elisym MCP agent"
|
|
2310
2485
|
},
|
|
2311
|
-
{
|
|
2312
|
-
type: "input",
|
|
2313
|
-
name: "capabilities",
|
|
2314
|
-
message: "Capabilities (comma-separated):",
|
|
2315
|
-
default: "mcp-gateway"
|
|
2316
|
-
},
|
|
2317
2486
|
{
|
|
2318
2487
|
type: "list",
|
|
2319
2488
|
name: "network",
|
|
@@ -2325,7 +2494,6 @@ program.command("init [name]").description("Create a new agent identity").option
|
|
|
2325
2494
|
]);
|
|
2326
2495
|
name = answers.name;
|
|
2327
2496
|
options.description = answers.description;
|
|
2328
|
-
options.capabilities = answers.capabilities;
|
|
2329
2497
|
options.network = answers.network;
|
|
2330
2498
|
}
|
|
2331
2499
|
if (options.network !== "devnet" && options.network !== "mainnet") {
|
|
@@ -2343,11 +2511,9 @@ program.command("init [name]").description("Create a new agent identity").option
|
|
|
2343
2511
|
const nostrSecretKey = generateSecretKey();
|
|
2344
2512
|
const nostrPubkey = getPublicKey(nostrSecretKey);
|
|
2345
2513
|
const solanaKeypair = Keypair.generate();
|
|
2346
|
-
const capabilities = options.capabilities.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((tag) => ({ name: tag, description: tag, tags: [tag], price: 0 }));
|
|
2347
2514
|
await saveAgentConfig(name, {
|
|
2348
2515
|
name,
|
|
2349
2516
|
description: options.description,
|
|
2350
|
-
capabilities,
|
|
2351
2517
|
relays: [...RELAYS],
|
|
2352
2518
|
nostrSecretKey: Buffer.from(nostrSecretKey).toString("hex"),
|
|
2353
2519
|
solanaSecretKey: bs58.encode(solanaKeypair.secretKey),
|
|
@@ -2370,13 +2536,16 @@ program.command("init [name]").description("Create a new agent identity").option
|
|
|
2370
2536
|
await runInstall({ agent: name });
|
|
2371
2537
|
}
|
|
2372
2538
|
});
|
|
2373
|
-
program.command("install").description("Install elisym MCP server into client configs").option("--client <name>", "Specific client (claude-desktop, cursor, windsurf)").option("--agent <name>", "Bind to specific agent").option("--list", "List detected clients").action(async (options) => {
|
|
2539
|
+
program.command("install").description("Install elisym MCP server into client configs").option("--client <name>", "Specific client (claude-desktop, claude-code, cursor, windsurf)").option("--agent <name>", "Bind to specific agent").option("--list", "List detected clients").action(async (options) => {
|
|
2374
2540
|
if (options.list) {
|
|
2375
2541
|
await runList();
|
|
2376
2542
|
} else {
|
|
2377
2543
|
await runInstall({ client: options.client, agent: options.agent });
|
|
2378
2544
|
}
|
|
2379
2545
|
});
|
|
2546
|
+
program.command("update").description("Refresh the elisym MCP entry in installed client configs").option("--client <name>", "Specific client (claude-desktop, claude-code, cursor, windsurf)").option("--agent <name>", "Override the agent binding").action(async (options) => {
|
|
2547
|
+
await runUpdate({ client: options.client, agent: options.agent });
|
|
2548
|
+
});
|
|
2380
2549
|
program.command("uninstall").description("Remove elisym from MCP client configs").option("--client <name>", "Specific client").action(async (options) => {
|
|
2381
2550
|
await runUninstall({ client: options.client });
|
|
2382
2551
|
});
|