paralith-mcp 0.4.4 → 0.4.6
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/dist/chains.json +23 -7
- package/dist/client.mjs +22 -5
- package/dist/graph.json +22 -22
- package/dist/http.mjs +239 -86
- package/dist/server.mjs +248 -105
- package/package.json +1 -1
package/dist/server.mjs
CHANGED
|
@@ -125,7 +125,6 @@ function walletShim(jwk) {
|
|
|
125
125
|
var enc, sha384, sha256, b64url, b64urlDec, jwkToAddress;
|
|
126
126
|
var init_ans104 = __esm({
|
|
127
127
|
"../../backend/native/ans104.mjs"() {
|
|
128
|
-
"use strict";
|
|
129
128
|
enc = new TextEncoder();
|
|
130
129
|
sha384 = (b) => crypto.createHash("sha384").update(b).digest();
|
|
131
130
|
sha256 = (b) => crypto.createHash("sha256").update(b).digest();
|
|
@@ -196,7 +195,6 @@ async function deriveWallets(phrase, env = process.env) {
|
|
|
196
195
|
var HOME, publicAddresses;
|
|
197
196
|
var init_keys = __esm({
|
|
198
197
|
"src/keys.mjs"() {
|
|
199
|
-
"use strict";
|
|
200
198
|
init_ans104();
|
|
201
199
|
HOME = process.env.PARALITH_MCP_HOME || path.join(os.homedir(), ".paralith", "mcp");
|
|
202
200
|
publicAddresses = (w) => ({
|
|
@@ -229,7 +227,6 @@ function saveAgent(name, entry) {
|
|
|
229
227
|
var FILE;
|
|
230
228
|
var init_agents = __esm({
|
|
231
229
|
"src/agents.mjs"() {
|
|
232
|
-
"use strict";
|
|
233
230
|
init_keys();
|
|
234
231
|
FILE = path2.join(HOME, "agents.json");
|
|
235
232
|
}
|
|
@@ -337,7 +334,6 @@ Phrases: ${slash(path3.join(HOME, "agents"))} (back them up; anything funded is
|
|
|
337
334
|
var WIN, NPX, LAUNCH, slash, installed, CLIENTS;
|
|
338
335
|
var init_setup = __esm({
|
|
339
336
|
"src/setup.mjs"() {
|
|
340
|
-
"use strict";
|
|
341
337
|
init_keys();
|
|
342
338
|
init_agents();
|
|
343
339
|
WIN = process.platform === "win32";
|
|
@@ -485,7 +481,6 @@ async function until(what, read, done, timeoutMs = 6e5, everyMs = 3e3) {
|
|
|
485
481
|
var HERE, DIST, graph, NODE, chains, PROCESS_ALIASES, ID, READ_ONLY, loaded, HTML, sleep;
|
|
486
482
|
var init_runtime = __esm({
|
|
487
483
|
"src/runtime.mjs"() {
|
|
488
|
-
"use strict";
|
|
489
484
|
init_ans104();
|
|
490
485
|
init_keys();
|
|
491
486
|
init_agents();
|
|
@@ -511,6 +506,65 @@ var init_runtime = __esm({
|
|
|
511
506
|
}
|
|
512
507
|
});
|
|
513
508
|
|
|
509
|
+
// package.json
|
|
510
|
+
var package_default;
|
|
511
|
+
var init_package = __esm({
|
|
512
|
+
"package.json"() {
|
|
513
|
+
package_default = {
|
|
514
|
+
name: "paralith-mcp",
|
|
515
|
+
version: "0.4.6",
|
|
516
|
+
description: "MCP server for Paralith on AO: an AI with one 24-word phrase plays Rune Realm, trades and bridges PUSD; plus paralith-bridge, the bridge operator CLI (TEST deployment).",
|
|
517
|
+
license: "UNLICENSED",
|
|
518
|
+
homepage: "https://docs.paralithmarkets.com/ai/mcp",
|
|
519
|
+
keywords: [
|
|
520
|
+
"mcp",
|
|
521
|
+
"model-context-protocol",
|
|
522
|
+
"ao",
|
|
523
|
+
"hyperbeam",
|
|
524
|
+
"arweave",
|
|
525
|
+
"game",
|
|
526
|
+
"agent"
|
|
527
|
+
],
|
|
528
|
+
type: "module",
|
|
529
|
+
bin: {
|
|
530
|
+
"paralith-mcp": "dist/server.mjs",
|
|
531
|
+
"paralith-bridge": "dist/bridge.mjs"
|
|
532
|
+
},
|
|
533
|
+
files: [
|
|
534
|
+
"dist",
|
|
535
|
+
"README.md"
|
|
536
|
+
],
|
|
537
|
+
publishConfig: {
|
|
538
|
+
access: "public"
|
|
539
|
+
},
|
|
540
|
+
scripts: {
|
|
541
|
+
build: "node scripts/build-client.mjs && node scripts/tools-doc.mjs",
|
|
542
|
+
"tools-doc": "node scripts/tools-doc.mjs",
|
|
543
|
+
start: "node src/server.mjs",
|
|
544
|
+
"start:http": "node src/http.mjs",
|
|
545
|
+
test: "node --test test/*.test.mjs"
|
|
546
|
+
},
|
|
547
|
+
engines: {
|
|
548
|
+
node: ">=20"
|
|
549
|
+
},
|
|
550
|
+
dependencies: {
|
|
551
|
+
"@modelcontextprotocol/ext-apps": "^2.0.3",
|
|
552
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
553
|
+
"@mysten/sui": "^2.34.0",
|
|
554
|
+
"@scure/bip39": "^2.4.0",
|
|
555
|
+
"@solana/web3.js": "^1.99.0",
|
|
556
|
+
"arweave-mnemonic-keys": "^0.0.9",
|
|
557
|
+
lodash: "^4.18.1",
|
|
558
|
+
viem: "^2.57.3",
|
|
559
|
+
zod: "^4.6.5"
|
|
560
|
+
},
|
|
561
|
+
devDependencies: {
|
|
562
|
+
esbuild: "^0.28.2"
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
|
|
514
568
|
// src/update.mjs
|
|
515
569
|
function check(now) {
|
|
516
570
|
checkedAt = now;
|
|
@@ -528,8 +582,8 @@ function updateNote(now = Date.now()) {
|
|
|
528
582
|
var VERSION, CHECK_MS, NOTE_MS, latest, checkedAt, notedAt, newer;
|
|
529
583
|
var init_update = __esm({
|
|
530
584
|
"src/update.mjs"() {
|
|
531
|
-
|
|
532
|
-
VERSION =
|
|
585
|
+
init_package();
|
|
586
|
+
VERSION = package_default.version;
|
|
533
587
|
CHECK_MS = 6 * 36e5;
|
|
534
588
|
NOTE_MS = 36e5;
|
|
535
589
|
latest = null;
|
|
@@ -588,7 +642,6 @@ The message WAS accepted (slot ${error?.slot ?? "?"}); its result could not be c
|
|
|
588
642
|
var migrationSeen, bigints, READ, OWN, WRITE;
|
|
589
643
|
var init_tool = __esm({
|
|
590
644
|
"src/tool.mjs"() {
|
|
591
|
-
"use strict";
|
|
592
645
|
init_runtime();
|
|
593
646
|
init_update();
|
|
594
647
|
migrationSeen = null;
|
|
@@ -658,13 +711,20 @@ function side(s) {
|
|
|
658
711
|
freeMovesUsed: Object.keys(s.freeUsed ?? {})
|
|
659
712
|
};
|
|
660
713
|
}
|
|
714
|
+
function sideOf(b, address) {
|
|
715
|
+
if (!address) return null;
|
|
716
|
+
if ((b.accepterAddress ?? b.accepter?.address) === address) return "accepter";
|
|
717
|
+
if ((b.challengerAddress ?? b.challenger?.address) === address) return "challenger";
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
661
720
|
function battle(b, address) {
|
|
662
721
|
if (!b || typeof b !== "object") return b;
|
|
663
|
-
const mine = b
|
|
722
|
+
const mine = sideOf(b, address);
|
|
664
723
|
const theirs = mine === "accepter" ? "challenger" : "accepter";
|
|
724
|
+
const label = (s) => !mine ? s : s === mine ? "you" : "opponent";
|
|
665
725
|
const turns = (b.turns ?? []).filter((t) => t.round === b.round - 1 || t.round === b.round).map((t) => ({
|
|
666
726
|
round: t.round,
|
|
667
|
-
by: t.attacker
|
|
727
|
+
by: label(t.attacker),
|
|
668
728
|
move: t.move,
|
|
669
729
|
damage: t.healthDamage,
|
|
670
730
|
shieldDamage: t.shieldDamage,
|
|
@@ -673,6 +733,7 @@ function battle(b, address) {
|
|
|
673
733
|
superEffective: t.superEffective,
|
|
674
734
|
notEffective: t.notEffective
|
|
675
735
|
}));
|
|
736
|
+
const sides = mine ? { you: side(b[mine]), opponent: side(b[theirs]) } : { challenger: side(b.challenger), accepter: side(b.accepter) };
|
|
676
737
|
return {
|
|
677
738
|
id: b.id,
|
|
678
739
|
kind: b.kind,
|
|
@@ -680,8 +741,7 @@ function battle(b, address) {
|
|
|
680
741
|
round: b.round,
|
|
681
742
|
...b.winner ? { winner: b.winner } : {},
|
|
682
743
|
...b.waitingOn?.length ? { waitingOn: b.waitingOn } : {},
|
|
683
|
-
|
|
684
|
-
opponent: side(b[theirs]),
|
|
744
|
+
...sides,
|
|
685
745
|
recentTurns: turns
|
|
686
746
|
};
|
|
687
747
|
}
|
|
@@ -697,7 +757,6 @@ function hunt(run2) {
|
|
|
697
757
|
var iso, uses, EXTRAS;
|
|
698
758
|
var init_views = __esm({
|
|
699
759
|
"src/views.mjs"() {
|
|
700
|
-
"use strict";
|
|
701
760
|
iso = (ms) => ms ? new Date(Number(ms)).toISOString() : void 0;
|
|
702
761
|
uses = (moves) => Object.fromEntries(Object.entries(moves ?? {}).map(([n, m]) => [n, m?.count ?? m]));
|
|
703
762
|
EXTRAS = ["rewards", "lootResult", "dailyClaimed", "economyResult", "withdrawal", "arenaLast", "lastHunt", "listing", "error"];
|
|
@@ -710,18 +769,25 @@ async function me() {
|
|
|
710
769
|
const { api, wallets } = await runtime();
|
|
711
770
|
return { api, address: wallets?.ao.address };
|
|
712
771
|
}
|
|
713
|
-
async function player2() {
|
|
714
|
-
const { api, address } = await me();
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
772
|
+
async function player2(address) {
|
|
773
|
+
const { api, address: mine } = await me();
|
|
774
|
+
const who = address ?? mine;
|
|
775
|
+
if (!who) throw new Error("This server has no wallet; pass an address.");
|
|
776
|
+
const p = await api.readPlayer(who);
|
|
777
|
+
if (!p) throw new Error(address ? `${address} has no Rune Realm account.` : "This wallet has no Rune Realm account yet. Call game_join first.");
|
|
718
778
|
return p;
|
|
719
779
|
}
|
|
780
|
+
async function findBattle(id) {
|
|
781
|
+
const fleet = await readKey("game", "battlefleet").catch(() => null);
|
|
782
|
+
const workers = (fleet?.workers ?? []).map((w) => w.workerProcessId).filter(Boolean);
|
|
783
|
+
const found = await Promise.all([readKey("game", `battle-op-${id}`), ...workers.map((w) => readKey(w, `battle-${id}`))].map((read) => read.catch(() => null)));
|
|
784
|
+
return found.find((b) => b && typeof b === "object") ?? null;
|
|
785
|
+
}
|
|
720
786
|
function registerGame(server) {
|
|
721
787
|
tool(
|
|
722
788
|
server,
|
|
723
789
|
"game_player",
|
|
724
|
-
"Read a Rune Realm player record (yours by default): gold,
|
|
790
|
+
"Read a Rune Realm player record (yours by default): gold, inventory, companions with energy/happiness/level/moves and pendingMoveOffer, loot boxes, arena record with arena.liveBattle, and liveHunt. Free, unsigned. Call this before deciding anything.",
|
|
725
791
|
{ address: z2.string().optional().describe("Another player's AO address; omit for yours.") },
|
|
726
792
|
async ({ address }) => {
|
|
727
793
|
const { api, address: mine } = await me();
|
|
@@ -737,7 +803,13 @@ function registerGame(server) {
|
|
|
737
803
|
"game_catalog",
|
|
738
804
|
"The game rules as data: activity costs/gains, arena terms, element effectiveness, free moves (Rally, Mend), hunt capture odds, items, level-up rules and every move pool. Free, unsigned.",
|
|
739
805
|
{},
|
|
740
|
-
async () =>
|
|
806
|
+
async () => {
|
|
807
|
+
const catalog = await (await me()).api.readCatalog();
|
|
808
|
+
if (catalog?.levelUp) {
|
|
809
|
+
catalog.levelUp = { ...catalog.levelUp, costDivisor: 32, cost: "ceil(targetLevel^2 / 32) Rune" };
|
|
810
|
+
}
|
|
811
|
+
return catalog;
|
|
812
|
+
},
|
|
741
813
|
READ
|
|
742
814
|
);
|
|
743
815
|
tool(
|
|
@@ -759,7 +831,11 @@ function registerGame(server) {
|
|
|
759
831
|
factions: factions?.map(({ members, ...f }) => f),
|
|
760
832
|
arenaTiers: tiers,
|
|
761
833
|
openChallenges: challenges,
|
|
762
|
-
leaderboard: leaderboard?.slice(0, 10)
|
|
834
|
+
leaderboard: leaderboard?.slice(0, 10).map(({ monster, ...row }) => {
|
|
835
|
+
if (!monster) return row;
|
|
836
|
+
const { exp, energy, happiness, ...companion2 } = companion(monster);
|
|
837
|
+
return { ...row, companion: companion2 };
|
|
838
|
+
})
|
|
763
839
|
};
|
|
764
840
|
},
|
|
765
841
|
READ
|
|
@@ -776,7 +852,7 @@ function registerGame(server) {
|
|
|
776
852
|
tool(
|
|
777
853
|
server,
|
|
778
854
|
"game_companion",
|
|
779
|
-
"Care for and manage companions. feed: 1 berry, +10
|
|
855
|
+
"Care for and manage companions. feed: 1 berry, +20 energy for a berry of its own element, +10 for any other. play: 10 energy + 1 berry, +25 happiness after 15 min. quest: 25 energy + 25 happiness, 1 h, then exp and Gold. claim: collect a finished play/quest. store (1 Rune; moves a companion into the collection) / retrieve / set_active / transfer manage the collection. adopt: once, if you have a faction but no companion.",
|
|
780
856
|
{
|
|
781
857
|
action: z2.enum(["feed", "play", "quest", "claim", "adopt", "store", "retrieve", "set_active", "transfer"]),
|
|
782
858
|
monster_id: z2.string().optional().describe("Companion id; omit for the active one."),
|
|
@@ -812,7 +888,7 @@ function registerGame(server) {
|
|
|
812
888
|
tool(
|
|
813
889
|
server,
|
|
814
890
|
"game_level_up",
|
|
815
|
-
"Level up the active companion when it has enough exp. Costs Rune. Allocate exactly the points the catalog says (levelUp.points), at most levelUp.maxPerStat in any one stat.",
|
|
891
|
+
"Level up the active companion when it has enough exp. Costs ceil(L^2/32) in-game Rune for target level L (1 up to level 5, 4 at 10, 13 at 20). Allocate exactly the points the catalog says (levelUp.points), at most levelUp.maxPerStat in any one stat. A pending move offer expires at the next level-up.",
|
|
816
892
|
{ attack: z2.number().int().min(0), defense: z2.number().int().min(0), speed: z2.number().int().min(0), health: z2.number().int().min(0) },
|
|
817
893
|
async (points) => (await me()).api.levelUp(points),
|
|
818
894
|
WRITE,
|
|
@@ -821,7 +897,7 @@ function registerGame(server) {
|
|
|
821
897
|
tool(
|
|
822
898
|
server,
|
|
823
899
|
"game_learn_move",
|
|
824
|
-
"Answer a pending move offer (every 5th level). Give replace to swap that move out; omit replace to decline. Final either way.",
|
|
900
|
+
"Answer a pending move offer (every 5th level). Give replace to swap that move out; omit replace to decline. Final either way. An unanswered offer expires at the next level-up.",
|
|
825
901
|
{ move: z2.string().describe("The offered move, exactly as in the player record."), replace: z2.string().optional() },
|
|
826
902
|
async ({ move, replace }) => (await me()).api.learnMove(move, replace),
|
|
827
903
|
WRITE,
|
|
@@ -845,27 +921,31 @@ function registerGame(server) {
|
|
|
845
921
|
WRITE,
|
|
846
922
|
asPlayer
|
|
847
923
|
);
|
|
924
|
+
tool(
|
|
925
|
+
server,
|
|
926
|
+
"game_shop_quote",
|
|
927
|
+
"The NPC realm shop's current Gold prices (bid/ask) and stock for berries, Scrolls and Rune. Free, unsigned.",
|
|
928
|
+
{},
|
|
929
|
+
async () => (await me()).api.readEconomy(),
|
|
930
|
+
READ
|
|
931
|
+
);
|
|
848
932
|
tool(
|
|
849
933
|
server,
|
|
850
934
|
"game_shop",
|
|
851
|
-
"
|
|
935
|
+
"Buy from or sell to the NPC realm shop for Gold (prices: game_shop_quote). Set max_total/min_total to bound slippage.",
|
|
852
936
|
{
|
|
853
|
-
action: z2.enum(["
|
|
854
|
-
item: z2.
|
|
855
|
-
quantity: z2.number().int().positive()
|
|
937
|
+
action: z2.enum(["buy", "sell"]),
|
|
938
|
+
item: z2.enum(SHOP_ITEMS),
|
|
939
|
+
quantity: z2.number().int().positive(),
|
|
856
940
|
max_total: z2.number().int().optional(),
|
|
857
941
|
min_total: z2.number().int().optional()
|
|
858
942
|
},
|
|
859
|
-
async ({ action, item, quantity, max_total, min_total }) =>
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
need(quantity, "quantity"),
|
|
866
|
-
{ maxTotal: max_total, minTotal: min_total }
|
|
867
|
-
);
|
|
868
|
-
},
|
|
943
|
+
async ({ action, item, quantity, max_total, min_total }) => (await me()).api.tradeGameShop(
|
|
944
|
+
action,
|
|
945
|
+
item,
|
|
946
|
+
quantity,
|
|
947
|
+
{ maxTotal: max_total, minTotal: min_total }
|
|
948
|
+
),
|
|
869
949
|
WRITE,
|
|
870
950
|
asPlayer
|
|
871
951
|
);
|
|
@@ -911,13 +991,23 @@ function registerGame(server) {
|
|
|
911
991
|
tool(
|
|
912
992
|
server,
|
|
913
993
|
"arena_battle",
|
|
914
|
-
"Read
|
|
915
|
-
{
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
994
|
+
"Read a battle: both sides' health, moves with uses left, round number and recent turns. Free. Defaults to your live battle; address reads that player's live battle; battle_id reads one battle directly (finished fights stay readable only briefly).",
|
|
995
|
+
{
|
|
996
|
+
address: z2.string().optional().describe("Whose live battle; omit for yours."),
|
|
997
|
+
battle_id: z2.string().optional().describe("A specific battle, e.g. from game_player arena.liveBattle.")
|
|
998
|
+
},
|
|
999
|
+
async ({ address, battle_id }) => {
|
|
1000
|
+
const { api, address: mine } = await me();
|
|
1001
|
+
const viewer = address ?? mine;
|
|
1002
|
+
if (battle_id) {
|
|
1003
|
+
const b = await findBattle(battle_id);
|
|
1004
|
+
return b ? seenBy(b, viewer) : { battle: null, note: `No battle ${battle_id} on the game or any battle worker.` };
|
|
1005
|
+
}
|
|
1006
|
+
if (!viewer) throw new Error("This server has no wallet; pass address or battle_id.");
|
|
1007
|
+
const p = await player2(viewer);
|
|
1008
|
+
const id = p.battleFleet?.battleId ?? p.activeBattleId;
|
|
1009
|
+
if (!id) return { battle: null, note: address ? `${address} has no live battle.` : "No live battle. Use arena_fight to start one." };
|
|
1010
|
+
return seenBy(p.battle?.id === id ? p.battle : await api.readBattle(id), viewer);
|
|
921
1011
|
},
|
|
922
1012
|
READ,
|
|
923
1013
|
battleView
|
|
@@ -955,7 +1045,7 @@ function registerGame(server) {
|
|
|
955
1045
|
tool(
|
|
956
1046
|
server,
|
|
957
1047
|
"hunt_begin",
|
|
958
|
-
"Start a hunt with a companion.
|
|
1048
|
+
"Start a hunt with a companion. Entry fee: 2 of each berry, not refunded. Up to 3 Rune and 1 Scroll go with the run and come back when it ends, unless a capture spends them.",
|
|
959
1049
|
{ monster_id: z2.string().describe("Companion to hunt with (see game_player).") },
|
|
960
1050
|
async ({ monster_id }) => (await me()).api.beginHunt(monster_id),
|
|
961
1051
|
WRITE,
|
|
@@ -964,14 +1054,14 @@ function registerGame(server) {
|
|
|
964
1054
|
tool(
|
|
965
1055
|
server,
|
|
966
1056
|
"hunt_state",
|
|
967
|
-
"Read
|
|
968
|
-
{},
|
|
969
|
-
async () => {
|
|
1057
|
+
"Read a live hunt run (yours by default): encounter, wild creature, round, status. Free.",
|
|
1058
|
+
{ address: z2.string().optional().describe("Another player's AO address; omit for yours.") },
|
|
1059
|
+
async ({ address }) => {
|
|
970
1060
|
const { api } = await me();
|
|
971
|
-
const route = (await player2()).hunt;
|
|
972
|
-
return route ? api.readHunt(route) : { hunt: null, note: "No live hunt. Use hunt_begin." };
|
|
1061
|
+
const route = (await player2(address)).hunt;
|
|
1062
|
+
return route ? api.readHunt(route) : { hunt: null, note: address ? `${address} has no live hunt.` : "No live hunt. Use hunt_begin." };
|
|
973
1063
|
},
|
|
974
|
-
|
|
1064
|
+
READ,
|
|
975
1065
|
huntView
|
|
976
1066
|
);
|
|
977
1067
|
tool(
|
|
@@ -1006,12 +1096,24 @@ function registerGame(server) {
|
|
|
1006
1096
|
WRITE,
|
|
1007
1097
|
huntView
|
|
1008
1098
|
);
|
|
1099
|
+
tool(
|
|
1100
|
+
server,
|
|
1101
|
+
"companion_market_browse",
|
|
1102
|
+
"The companion market (priced in in-game Rune): current listings and recent sales. Free, unsigned.",
|
|
1103
|
+
{},
|
|
1104
|
+
async () => {
|
|
1105
|
+
const { api } = await me();
|
|
1106
|
+
const [listings, history] = await Promise.all([api.readMarket(), api.readMarketHistory()]);
|
|
1107
|
+
return { listings, history };
|
|
1108
|
+
},
|
|
1109
|
+
READ
|
|
1110
|
+
);
|
|
1009
1111
|
tool(
|
|
1010
1112
|
server,
|
|
1011
1113
|
"companion_market",
|
|
1012
|
-
"
|
|
1114
|
+
"Trade companions for in-game Rune (listings: companion_market_browse). list: sell a companion from your collection (never the active one; game_companion store moves it there for 1 Rune). buy / cancel: by listing_id.",
|
|
1013
1115
|
{
|
|
1014
|
-
action: z2.enum(["
|
|
1116
|
+
action: z2.enum(["list", "buy", "cancel"]),
|
|
1015
1117
|
monster_id: z2.string().optional(),
|
|
1016
1118
|
price: z2.number().int().min(1).max(1e6).optional(),
|
|
1017
1119
|
listing_id: z2.string().optional()
|
|
@@ -1019,8 +1121,6 @@ function registerGame(server) {
|
|
|
1019
1121
|
async ({ action, monster_id, price, listing_id }) => {
|
|
1020
1122
|
const { api } = await me();
|
|
1021
1123
|
switch (action) {
|
|
1022
|
-
case "browse":
|
|
1023
|
-
return { listings: await api.readMarket(), history: await api.readMarketHistory() };
|
|
1024
1124
|
case "list":
|
|
1025
1125
|
return api.listMonster(need(monster_id, "monster_id"), need(price, "price"));
|
|
1026
1126
|
case "buy":
|
|
@@ -1048,7 +1148,7 @@ function registerGame(server) {
|
|
|
1048
1148
|
tool(
|
|
1049
1149
|
server,
|
|
1050
1150
|
"element_claim",
|
|
1051
|
-
"Claim today's free TEST element tokens
|
|
1151
|
+
"Claim today's free TEST element tokens: 1-10 of one element (chosen by the contract) per wallet per UTC day, until that element's 2,000-token daily cap across all wallets is spent; after that, claims are refused until the next day.",
|
|
1052
1152
|
{},
|
|
1053
1153
|
async () => {
|
|
1054
1154
|
const { api, address } = await me();
|
|
@@ -1058,9 +1158,6 @@ function registerGame(server) {
|
|
|
1058
1158
|
WRITE
|
|
1059
1159
|
);
|
|
1060
1160
|
}
|
|
1061
|
-
async function battleView(b) {
|
|
1062
|
-
return b?.id ? battle(b, (await me()).address) : b;
|
|
1063
|
-
}
|
|
1064
1161
|
async function attackView(p) {
|
|
1065
1162
|
if (!p?.address) return p;
|
|
1066
1163
|
const { address, gold, battlesRemaining, wins, losses, arenaLast } = p;
|
|
@@ -1077,16 +1174,18 @@ function need(value, name) {
|
|
|
1077
1174
|
if (value === void 0 || value === null || value === "") throw new Error(`${name} is required for this action`);
|
|
1078
1175
|
return value;
|
|
1079
1176
|
}
|
|
1080
|
-
var FACTIONS, BERRIES, asPlayer, huntView;
|
|
1177
|
+
var FACTIONS, BERRIES, SHOP_ITEMS, seenBy, asPlayer, battleView, huntView;
|
|
1081
1178
|
var init_game = __esm({
|
|
1082
1179
|
"src/game.mjs"() {
|
|
1083
|
-
"use strict";
|
|
1084
1180
|
init_runtime();
|
|
1085
1181
|
init_tool();
|
|
1086
1182
|
init_views();
|
|
1087
1183
|
FACTIONS = ["Sky Nomads", "Aqua Guardians", "Inferno Blades", "Stone Titans"];
|
|
1088
1184
|
BERRIES = ["air_berry", "fire_berry", "rock_berry", "water_berry"];
|
|
1185
|
+
SHOP_ITEMS = [...BERRIES, "scroll", "rune"];
|
|
1186
|
+
seenBy = (b, address) => b && typeof b === "object" ? Object.defineProperty(b, "viewer", { value: address, enumerable: false, configurable: true }) : b;
|
|
1089
1187
|
asPlayer = (r) => r?.address && r?.inventory ? player(r) : r;
|
|
1188
|
+
battleView = (b) => b?.id ? battle(b, b.viewer) : b;
|
|
1090
1189
|
huntView = (r) => r?.runId ? hunt(r) : asPlayer(r);
|
|
1091
1190
|
}
|
|
1092
1191
|
});
|
|
@@ -1111,9 +1210,14 @@ function toWire(t, m, price, quantity) {
|
|
|
1111
1210
|
const baseAtoms = parseAmount(quantity, baseDen);
|
|
1112
1211
|
if (baseAtoms % lot !== 0n) throw new Error(`Quantity moves in steps of ${formatAtoms(lot, baseDen)} ${m.base}.`);
|
|
1113
1212
|
const perUnit = parseAmount(price, t.den(m.quote));
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1213
|
+
const unit = 10n ** BigInt(baseDen);
|
|
1214
|
+
const tick = BigInt(Math.max(1, Number(m.tick ?? 1)));
|
|
1215
|
+
const scaled = perUnit * lot;
|
|
1216
|
+
if (scaled % unit !== 0n || scaled / unit % tick !== 0n) {
|
|
1217
|
+
const step = tick * unit % lot === 0n ? formatAtoms(tick * unit / lot, t.den(m.quote)) : null;
|
|
1218
|
+
throw new Error(step ? `Price moves in steps of ${step} ${m.quote} per ${m.base}.` : `Price must be a whole multiple of ${tick} ${m.quote} atoms per lot of ${formatAtoms(lot, baseDen)} ${m.base}.`);
|
|
1219
|
+
}
|
|
1220
|
+
return { lots: (baseAtoms / lot).toString(), perLot: (scaled / unit).toString() };
|
|
1117
1221
|
}
|
|
1118
1222
|
function registerExchange(server) {
|
|
1119
1223
|
tool(
|
|
@@ -1138,22 +1242,21 @@ function registerExchange(server) {
|
|
|
1138
1242
|
const { api } = await runtime();
|
|
1139
1243
|
const book = (await api.readVenueBook(t.process))?.[m.id];
|
|
1140
1244
|
if (!book) return { market: m.id, book: null };
|
|
1141
|
-
const
|
|
1142
|
-
const
|
|
1143
|
-
const level = (l) => ({ price: unitPrice(l.price), quantity: units(l.quantity), orders: l.orders });
|
|
1245
|
+
const price = (perLot) => unitPrice(t, m, perLot);
|
|
1246
|
+
const level = (l) => ({ price: price(l.price), quantity: units(t, m, l.quantity), orders: l.orders });
|
|
1144
1247
|
return {
|
|
1145
1248
|
market: m.id,
|
|
1146
1249
|
units: `price in ${m.quote} per 1 ${m.base}; quantity in ${m.base}`,
|
|
1147
|
-
bestBid: book.bestBid ?
|
|
1148
|
-
bestAsk: book.bestAsk ?
|
|
1250
|
+
bestBid: book.bestBid ? price(book.bestBid) : null,
|
|
1251
|
+
bestAsk: book.bestAsk ? price(book.bestAsk) : null,
|
|
1149
1252
|
bids: (book.depth?.bids ?? []).slice(0, 10).map(level),
|
|
1150
1253
|
asks: (book.depth?.asks ?? []).slice(0, 10).map(level),
|
|
1151
|
-
band: book.band && { low:
|
|
1254
|
+
band: book.band && { low: price(book.band.low), high: price(book.band.high) },
|
|
1152
1255
|
today: book.candles?.at(-1) && {
|
|
1153
|
-
open:
|
|
1154
|
-
high:
|
|
1155
|
-
low:
|
|
1156
|
-
close:
|
|
1256
|
+
open: price(book.candles.at(-1).o),
|
|
1257
|
+
high: price(book.candles.at(-1).h),
|
|
1258
|
+
low: price(book.candles.at(-1).l),
|
|
1259
|
+
close: price(book.candles.at(-1).c),
|
|
1157
1260
|
trades: book.candles.at(-1).n
|
|
1158
1261
|
}
|
|
1159
1262
|
};
|
|
@@ -1163,7 +1266,7 @@ function registerExchange(server) {
|
|
|
1163
1266
|
tool(
|
|
1164
1267
|
server,
|
|
1165
1268
|
"exchange_position",
|
|
1166
|
-
"Balances at a venue (free,
|
|
1269
|
+
"Balances at a venue (free, and where each asset sits) with open orders and recent fills, all in human units; yours unless address is given. Free.",
|
|
1167
1270
|
{ venue: VENUE, address: z3.string().optional() },
|
|
1168
1271
|
async ({ venue, address }) => {
|
|
1169
1272
|
const t = await terms(venue);
|
|
@@ -1171,7 +1274,33 @@ function registerExchange(server) {
|
|
|
1171
1274
|
const who = address ?? wallets?.ao.address;
|
|
1172
1275
|
if (!who) throw new Error("This server has no wallet; pass an address.");
|
|
1173
1276
|
const p = await api.readVenuePosition(t.process, who);
|
|
1174
|
-
|
|
1277
|
+
const market = (row) => t.markets[row.market] ?? marketFor(t, row.item);
|
|
1278
|
+
const order = ({ lot, ...o }) => {
|
|
1279
|
+
const m = { ...market(o), ...lot ? { lot } : {} };
|
|
1280
|
+
return {
|
|
1281
|
+
...o,
|
|
1282
|
+
price: unitPrice(t, m, o.price),
|
|
1283
|
+
quantity: units(t, m, o.quantity),
|
|
1284
|
+
...o.remaining !== void 0 ? { remaining: units(t, m, o.remaining) } : {}
|
|
1285
|
+
};
|
|
1286
|
+
};
|
|
1287
|
+
const fill = (f) => {
|
|
1288
|
+
const m = market(f);
|
|
1289
|
+
return {
|
|
1290
|
+
...f,
|
|
1291
|
+
price: unitPrice(t, m, f.price),
|
|
1292
|
+
quantity: units(t, m, f.quantity),
|
|
1293
|
+
...f.fee !== void 0 ? { fee: formatAtoms(BigInt(f.fee), t.den(m.quote)) } : {}
|
|
1294
|
+
};
|
|
1295
|
+
};
|
|
1296
|
+
return {
|
|
1297
|
+
account: p.account ?? who,
|
|
1298
|
+
units: "price in quote per 1 base unit; quantity in base units; fee in quote",
|
|
1299
|
+
free: human(t, p.free),
|
|
1300
|
+
...p.locations ? { locations: Object.fromEntries(Object.entries(p.locations).map(([asset, at]) => [asset, Object.fromEntries(Object.entries(at).map(([where, atoms]) => [where, formatAtoms(atoms, t.den(asset))]))])) } : {},
|
|
1301
|
+
orders: (p.orders ?? []).map(order),
|
|
1302
|
+
fills: (p.fills ?? []).map(fill)
|
|
1303
|
+
};
|
|
1175
1304
|
},
|
|
1176
1305
|
READ
|
|
1177
1306
|
);
|
|
@@ -1269,14 +1398,15 @@ function registerExchange(server) {
|
|
|
1269
1398
|
WRITE
|
|
1270
1399
|
);
|
|
1271
1400
|
}
|
|
1272
|
-
var VENUE, venueProcess, human;
|
|
1401
|
+
var VENUE, venueProcess, unitPrice, units, human;
|
|
1273
1402
|
var init_exchange = __esm({
|
|
1274
1403
|
"src/exchange.mjs"() {
|
|
1275
|
-
"use strict";
|
|
1276
1404
|
init_runtime();
|
|
1277
1405
|
init_tool();
|
|
1278
1406
|
VENUE = z3.enum(["game", "token"]).describe("game: items vs Gold. token: element tokens vs TEST-RUNE.");
|
|
1279
1407
|
venueProcess = (venue) => venue === "game" ? graph.processes.internalVenue : graph.processes.externalVenue;
|
|
1408
|
+
unitPrice = (t, m, perLot) => formatAtoms(BigInt(perLot) * 10n ** BigInt(t.den(m.base)) / BigInt(m.lot), t.den(m.quote));
|
|
1409
|
+
units = (t, m, lots) => formatAtoms(BigInt(lots) * BigInt(m.lot), t.den(m.base));
|
|
1280
1410
|
human = (t, free) => Object.fromEntries(Object.entries(free ?? {}).map(([asset, atoms]) => [asset, formatAtoms(atoms, t.den(asset))]));
|
|
1281
1411
|
}
|
|
1282
1412
|
});
|
|
@@ -1708,7 +1838,6 @@ function registerBridge(server) {
|
|
|
1708
1838
|
var DAILY_FAUCET, DAY_MS, CHAIN, PUSD, faucetToken, pusdBalance;
|
|
1709
1839
|
var init_bridge = __esm({
|
|
1710
1840
|
"src/bridge.mjs"() {
|
|
1711
|
-
"use strict";
|
|
1712
1841
|
init_runtime();
|
|
1713
1842
|
init_tool();
|
|
1714
1843
|
DAILY_FAUCET = 100000000n;
|
|
@@ -1878,7 +2007,6 @@ function registerDao(server) {
|
|
|
1878
2007
|
var RUNE, DEN, tags, runeView;
|
|
1879
2008
|
var init_dao = __esm({
|
|
1880
2009
|
"src/dao.mjs"() {
|
|
1881
|
-
"use strict";
|
|
1882
2010
|
init_runtime();
|
|
1883
2011
|
init_tool();
|
|
1884
2012
|
RUNE = graph.processes.rune;
|
|
@@ -2068,7 +2196,6 @@ function registerVaults(server) {
|
|
|
2068
2196
|
var VENUE2, STRATEGY, venueProcess2, DAY_MS2, pct, iso2;
|
|
2069
2197
|
var init_vaults = __esm({
|
|
2070
2198
|
"src/vaults.mjs"() {
|
|
2071
|
-
"use strict";
|
|
2072
2199
|
init_runtime();
|
|
2073
2200
|
init_tool();
|
|
2074
2201
|
VENUE2 = z6.enum(["game", "token"]).describe("game: items vs Gold. token: element tokens vs TEST-RUNE.");
|
|
@@ -2154,7 +2281,6 @@ ${where}` }] };
|
|
|
2154
2281
|
var GAME, TRADE, URI, HERE2, link, VIEWS;
|
|
2155
2282
|
var init_show = __esm({
|
|
2156
2283
|
"src/show.mjs"() {
|
|
2157
|
-
"use strict";
|
|
2158
2284
|
init_runtime();
|
|
2159
2285
|
GAME = (process.env.PARALITH_GAME_URL || "https://game.paralithmarkets.com").replace(/\/$/, "");
|
|
2160
2286
|
TRADE = (process.env.PARALITH_TRADE_URL || "https://trade.paralithmarkets.com").replace(/\/$/, "");
|
|
@@ -2272,7 +2398,6 @@ function registerProgress(server) {
|
|
|
2272
2398
|
var VENUES, count;
|
|
2273
2399
|
var init_progress = __esm({
|
|
2274
2400
|
"src/progress.mjs"() {
|
|
2275
|
-
"use strict";
|
|
2276
2401
|
init_runtime();
|
|
2277
2402
|
init_tool();
|
|
2278
2403
|
init_agents();
|
|
@@ -2294,9 +2419,7 @@ import { z as z9 } from "zod";
|
|
|
2294
2419
|
function buildServer() {
|
|
2295
2420
|
const server = new McpServer(
|
|
2296
2421
|
{ name: "paralith", version: VERSION },
|
|
2297
|
-
{ instructions: READ_ONLY ?
|
|
2298
|
-
|
|
2299
|
-
${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
2422
|
+
{ instructions: READ_ONLY ? READ_ONLY_INSTRUCTIONS : INSTRUCTIONS }
|
|
2300
2423
|
);
|
|
2301
2424
|
tool(
|
|
2302
2425
|
server,
|
|
@@ -2323,7 +2446,7 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
|
2323
2446
|
tool(
|
|
2324
2447
|
server,
|
|
2325
2448
|
"read_state",
|
|
2326
|
-
`Read any published key of any process, free: /<process>~process@1.0/now/<key>. process is an id or an alias (${Object.keys(PROCESS_ALIASES).join(", ")}). Returns null when absent.`,
|
|
2449
|
+
`Read any published key of any process, free: /<process>~process@1.0/now/<key>. process is an id or an alias (${Object.keys(PROCESS_ALIASES).join(", ")}). Returns null when absent. Common keys: game: player-<address>, catalogref (the catalog's id, not catalog), leaderboard, factions, arenatiers, challenges, economy, economybook, market, markethistory, battlefleet, huntconfig, access. rune and *-token: balance-<address>, tokeninfo (not info), totalsupply. pusd: balance-<address>, bridgeinfo, withdrawals. dao: daoinfo, proposals. game-venue and token-venue: balance-<address>, vaultinfo, vaultpairs.`,
|
|
2327
2450
|
{ process: z9.string(), key: z9.string() },
|
|
2328
2451
|
async ({ process: process2, key }) => readKey(process2, key),
|
|
2329
2452
|
READ
|
|
@@ -2331,7 +2454,7 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
|
2331
2454
|
tool(
|
|
2332
2455
|
server,
|
|
2333
2456
|
"send_message",
|
|
2334
|
-
"Escape hatch: sign and send a raw message to any process and return its reply. Prefer the specific tools; use this only for an action they do not cover. Tag values must be strings; never use a tag named Target.",
|
|
2457
|
+
"Escape hatch: sign and send a raw message to any process and return its reply. Prefer the specific tools; use this only for an action they do not cover. Tag values must be strings; never use a tag named Target, Signature or Epoch.",
|
|
2335
2458
|
{
|
|
2336
2459
|
process: z9.string(),
|
|
2337
2460
|
tags: z9.record(z9.string(), z9.string()).describe('e.g. {"Action": "Pass.Info"}'),
|
|
@@ -2339,7 +2462,8 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
|
2339
2462
|
push_outbox: z9.boolean().optional().describe("Deliver the messages this one emits to other processes (e.g. a Transfer to a process).")
|
|
2340
2463
|
},
|
|
2341
2464
|
async ({ process: process2, tags: tags2, data, push_outbox }) => {
|
|
2342
|
-
|
|
2465
|
+
const reserved = Object.keys(tags2).find((k) => ["target", "signature", "epoch"].includes(k.toLowerCase().replace(/[-_]/g, "")));
|
|
2466
|
+
if (reserved) throw new Error(`${reserved} is not a usable tag name (Target, Signature and Epoch are reserved).`);
|
|
2343
2467
|
const { api } = await runtime();
|
|
2344
2468
|
return api.rawSend(
|
|
2345
2469
|
Object.entries(tags2).map(([name, value]) => ({ name, value })),
|
|
@@ -2369,10 +2493,9 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
|
2369
2493
|
registerProgress(server);
|
|
2370
2494
|
return server;
|
|
2371
2495
|
}
|
|
2372
|
-
var DOCS, INSTRUCTIONS,
|
|
2496
|
+
var DOCS, INSTRUCTIONS, READ_ONLY_INSTRUCTIONS;
|
|
2373
2497
|
var init_build = __esm({
|
|
2374
2498
|
"src/build.mjs"() {
|
|
2375
|
-
"use strict";
|
|
2376
2499
|
init_runtime();
|
|
2377
2500
|
init_keys();
|
|
2378
2501
|
init_tool();
|
|
@@ -2389,29 +2512,33 @@ var init_build = __esm({
|
|
|
2389
2512
|
Everything is TEST-prefixed while unreleased. Reads are free; every write is a signed message (a few seconds round trip, longer under load).
|
|
2390
2513
|
|
|
2391
2514
|
Start: wallet -> game_player. No account? game_join (pick a faction).
|
|
2392
|
-
Core loop: game_daily once a day; game_companion feed/play
|
|
2393
|
-
game_level_up when exp allows; game_learn_move when an offer is pending.
|
|
2515
|
+
Core loop: game_daily once a day; game_companion feed/play keep energy and happiness up, quest then claim earns exp and Gold;
|
|
2516
|
+
game_level_up when exp allows; game_learn_move when an offer is pending (it expires at the next level-up).
|
|
2394
2517
|
Arena: arena_enter (25 energy + 25 happiness, 4 fights), arena_fight mode=bot, then arena_attack each round
|
|
2395
2518
|
(read arena_battle for moves and uses left; Rally and Mend are free once each), arena_end leave when done.
|
|
2396
|
-
Hunt: hunt_begin
|
|
2519
|
+
Hunt: hunt_begin (entry fee 2 of each berry, not refunded; up to 3 Rune + 1 Scroll set aside and returned unless a capture spends them)
|
|
2520
|
+
-> hunt_act search -> attack until defeated -> capture (1-3 Rune + a Scroll) or end. One encounter per hunt.
|
|
2397
2521
|
Markets: exchange_markets / exchange_book / exchange_order on venue "game" (items vs Gold) or "token" (elements vs TEST-RUNE).
|
|
2398
2522
|
Vaults (pooled liquidity, one amm/active/grid per market): vault_list, vault_position, vault_deposit, vault_shares (withdraw/lock/burn), vault_fund, vault_crank.
|
|
2399
2523
|
Rune: rune_move withdraw (game -> token) / deposit (token -> game). Bridge: bridge_balances, bridge_faucet, bridge_deposit, bridge_redeem.
|
|
2400
2524
|
DAO (stake TEST-RUNE; a passed proposal may send one attached message): dao_info, dao_proposals, dao_stake stake/unstake/withdraw, dao_propose, dao_vote.
|
|
2401
2525
|
|
|
2402
2526
|
HOW RESOURCES FLOW. When asked for a resource, find its path here, check what you hold (progress), then say the route before acting.
|
|
2403
|
-
- Gold (in-game only, never leaves the game). Earn:
|
|
2404
|
-
selling berries/Scrolls/Rune to the shop (game_shop sell) or on the game venue.
|
|
2527
|
+
- Gold (in-game only, never leaves the game). Earn: quest claims and arena bot wins, which share one 60 Gold allowance per 20 h
|
|
2528
|
+
(play pays happiness only); selling berries/Scrolls/Rune to the shop (game_shop sell) or on the game venue.
|
|
2529
|
+
Spend: arena stakes, shop buys, game-venue buys.
|
|
2405
2530
|
- Berries and Scrolls. Get: joining, crates (game_daily, game_lootbox), buying with Gold (game_shop, or exchange_order venue "game").
|
|
2406
|
-
Use: feed the companion, hunt
|
|
2531
|
+
Use: feed the companion, the hunt entry fee (2 of each berry), arena boosts; a Scroll plus 1-3 Rune for a hunt capture.
|
|
2407
2532
|
- Rune exists twice: in-game Rune and the TEST-RUNE wallet token; rune_move converts 1:1 either way.
|
|
2408
|
-
Get Rune: (1) the shop, only if
|
|
2409
|
-
(3) the token route
|
|
2410
|
-
sell that element for TEST-RUNE -> rune_move deposit.
|
|
2411
|
-
|
|
2533
|
+
Get Rune: (1) the shop, only if game_shop_quote shows an ask (it often only bids); (2) sell a companion on companion_market;
|
|
2534
|
+
(3) the token route: element_claim (free, 1-10 of one element per wallet per UTC day until that element's 2,000/day
|
|
2535
|
+
global cap is spent) -> exchange_order venue "token" sell that element for TEST-RUNE -> rune_move deposit.
|
|
2536
|
+
Public TEST accounts accrue no Rune from game_daily (pass holders only).
|
|
2537
|
+
Spend in-game Rune: game_level_up (ceil(L^2/32) for level L), hunt capture, companion_market buys, game_companion store (1 Rune).
|
|
2538
|
+
TEST-RUNE: token-venue buys, vaults, dao_stake.
|
|
2412
2539
|
- Element tokens (TEST-EARTH/AIR/FIRE/WATER): element_claim daily; trade against TEST-RUNE on the token venue; vault liquidity.
|
|
2413
2540
|
- PUSD: bridge in TEST-USDC from Base, Solana or Sui (needs that chain's gas, which the user funds; bridge_faucet gives TEST-USDC).
|
|
2414
|
-
No PUSD market is listed yet.
|
|
2541
|
+
No PUSD market is listed yet. bridge_redeem waits for k attestor signatures and submits the release (needs destination-chain gas).
|
|
2415
2542
|
- Vaults: deposit both sides of a market to earn from its strategy; withdraw with vault_shares.
|
|
2416
2543
|
|
|
2417
2544
|
To report how you (or every agent set up on this machine) are doing, call progress (who: "all" for every agent); it also lists what needs doing next.
|
|
@@ -2422,8 +2549,24 @@ Show once per thing, not once per round.
|
|
|
2422
2549
|
|
|
2423
2550
|
Rules: if a tool says a write WAS accepted but unconfirmed, never resend it; re-read state instead.
|
|
2424
2551
|
A refusal ({"error": ...}) costs nothing. Use game_catalog for exact costs and move stats; docs at ${DOCS}/llms-full.txt.`;
|
|
2425
|
-
|
|
2426
|
-
To play, trade or bridge, run the local server with a wallet phrase: ${DOCS}/ai/mcp
|
|
2552
|
+
READ_ONLY_INSTRUCTIONS = `This endpoint is READ-ONLY: it explains the protocol and reads live state for any address, free.
|
|
2553
|
+
To play, trade or bridge, run the local server with a wallet phrase: ${DOCS}/ai/mcp
|
|
2554
|
+
|
|
2555
|
+
Paralith on AO (HyperBEAM): Rune Realm (a companion game), two order books, and the PUSD bridge.
|
|
2556
|
+
Everything is TEST-prefixed while unreleased. Pass an address wherever a tool takes one.
|
|
2557
|
+
|
|
2558
|
+
- Game: game_player (account, companions, live battle or hunt), game_catalog (rules, costs, move stats),
|
|
2559
|
+
game_world (factions, arena tiers, open challenges, leaderboard), arena_battle (address or battle_id), hunt_state (address),
|
|
2560
|
+
game_shop_quote (NPC shop prices and stock), companion_market_browse (listings and recent sales).
|
|
2561
|
+
- Markets: exchange_markets / exchange_book / exchange_position on venue "game" (items vs Gold) or "token" (elements vs TEST-RUNE);
|
|
2562
|
+
vault_list, vault_position.
|
|
2563
|
+
- Bridge and DAO: bridge_info, bridge_status, dao_info, dao_proposals, dao_stake_info.
|
|
2564
|
+
- Anything else: progress (one address across everything), read_state (any published key), protocol_docs.
|
|
2565
|
+
|
|
2566
|
+
SHOW IT. Watching beats reading: call show for anything worth seeing (a fight as it happens, a companion, a book, a vault,
|
|
2567
|
+
a bridge transfer). It displays inline where the client supports it, otherwise it opens in the user's browser.
|
|
2568
|
+
|
|
2569
|
+
Docs: ${DOCS}/llms-full.txt.`;
|
|
2427
2570
|
}
|
|
2428
2571
|
});
|
|
2429
2572
|
|