paralith-mcp 0.3.0 → 0.3.2
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 +15 -1
- package/dist/http.mjs +86 -8
- package/dist/server.mjs +93 -9
- package/package.json +1 -1
package/dist/chains.json
CHANGED
|
@@ -146,5 +146,19 @@
|
|
|
146
146
|
"solana": "9eVvxEPKgpQ4Y2BZV8BWVAeRHWWfSEJy3vrM2AFNzdQ2",
|
|
147
147
|
"sui": "0x46bd8f40263f6e056262f82f13c61d0849d813a030cde4c5bd6a8dd768144e9f",
|
|
148
148
|
"ao": "z2OMYtbWHqNZY01ehkN0tsepznlrZQW-6dXPQO5lxDM"
|
|
149
|
-
}
|
|
149
|
+
},
|
|
150
|
+
"nodes": [
|
|
151
|
+
{
|
|
152
|
+
"ao": "tkqULqMDeHKXCN79Cm_bDIV560JxXl6pBSmdPgxqwSw",
|
|
153
|
+
"url": "https://hyperbeam.tylerw.ai"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"ao": "lcP5YsqL7SGNgylyzqlEO2M7VU6ntGUGNSSNO2WeytI",
|
|
157
|
+
"url": "https://hb.paralithmarkets.com"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"ao": "yUPIU4jjmkeR1RVACTj5__KavHcMoNoQ_Ly80F7u3GQ",
|
|
161
|
+
"url": "https://hb.randao.net"
|
|
162
|
+
}
|
|
163
|
+
]
|
|
150
164
|
}
|
package/dist/http.mjs
CHANGED
|
@@ -304,15 +304,60 @@ import { z as z9 } from "zod";
|
|
|
304
304
|
|
|
305
305
|
// src/tool.mjs
|
|
306
306
|
import { z } from "zod";
|
|
307
|
+
|
|
308
|
+
// src/update.mjs
|
|
309
|
+
var VERSION = "0.3.2";
|
|
310
|
+
var CHECK_MS = 6 * 36e5;
|
|
311
|
+
var NOTE_MS = 36e5;
|
|
312
|
+
var latest = null;
|
|
313
|
+
var checkedAt = 0;
|
|
314
|
+
var notedAt = 0;
|
|
315
|
+
var newer = (a, b) => {
|
|
316
|
+
const [x, y] = [a, b].map((v) => v.split(".").map(Number));
|
|
317
|
+
for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] > y[i];
|
|
318
|
+
return false;
|
|
319
|
+
};
|
|
320
|
+
function check(now) {
|
|
321
|
+
checkedAt = now;
|
|
322
|
+
fetch("https://registry.npmjs.org/paralith-mcp/latest", { signal: AbortSignal.timeout(1e4) }).then((r) => r.ok ? r.json() : null).then((j) => {
|
|
323
|
+
if (j?.version) latest = j.version;
|
|
324
|
+
}, () => {
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
function updateNote(now = Date.now()) {
|
|
328
|
+
if (now - checkedAt > CHECK_MS) check(now);
|
|
329
|
+
if (!latest || !newer(latest, VERSION) || now - notedAt < NOTE_MS) return null;
|
|
330
|
+
notedAt = now;
|
|
331
|
+
return `paralith-mcp ${latest} is out (this is ${VERSION}). Tell the user to restart this app to get it.`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/tool.mjs
|
|
335
|
+
var migrationSeen = null;
|
|
336
|
+
async function migrationRefusal(read = readKey, now = Date.now()) {
|
|
337
|
+
if (!migrationSeen || now - migrationSeen.at > 15e3) {
|
|
338
|
+
migrationSeen = { at: now, value: await read("game", "migration").catch(() => null) };
|
|
339
|
+
}
|
|
340
|
+
const m = migrationSeen.value;
|
|
341
|
+
if (!m || typeof m !== "object" || m.phase === "live") return null;
|
|
342
|
+
if (m.phase === "retired") {
|
|
343
|
+
return `Paralith has moved to new processes (the game is now ${m.successor}). Nothing was sent. Update paralith-mcp to its latest version to use them.`;
|
|
344
|
+
}
|
|
345
|
+
return "A migration is in progress: Paralith is paused while every balance moves to new processes. Nothing was sent, and nothing is lost. Reads still work; try writes again later.";
|
|
346
|
+
}
|
|
307
347
|
function tool(server, name, description, inputSchema, run, annotations = {}, view = null) {
|
|
308
348
|
if (READ_ONLY && annotations !== READ) return;
|
|
309
349
|
const schema = view ? { ...inputSchema, full: z.boolean().optional().describe("Return the raw record instead of the compact view.") } : inputSchema;
|
|
310
350
|
server.registerTool(name, { description, inputSchema: schema, annotations }, async (args) => {
|
|
311
351
|
try {
|
|
352
|
+
if (annotations === WRITE) {
|
|
353
|
+
const refusal = await migrationRefusal();
|
|
354
|
+
if (refusal) return { isError: true, content: [{ type: "text", text: refusal }] };
|
|
355
|
+
}
|
|
312
356
|
const raw = await run(args ?? {});
|
|
313
357
|
const value = view && !args?.full ? await view(raw) : raw;
|
|
314
358
|
const text = typeof value === "string" ? value : JSON.stringify(value, bigints, 2);
|
|
315
|
-
|
|
359
|
+
const note = READ_ONLY ? null : updateNote();
|
|
360
|
+
return { content: [{ type: "text", text: text ?? "null" }, ...note ? [{ type: "text", text: note }] : []] };
|
|
316
361
|
} catch (error) {
|
|
317
362
|
return { isError: true, content: [{ type: "text", text: explain(error) }] };
|
|
318
363
|
}
|
|
@@ -562,7 +607,7 @@ function registerGame(server) {
|
|
|
562
607
|
tool(
|
|
563
608
|
server,
|
|
564
609
|
"game_daily",
|
|
565
|
-
"Claim the daily crate and Rune. Once per UTC day.",
|
|
610
|
+
"Claim the daily crate (and accrued Rune, pass holders only). Once per UTC day.",
|
|
566
611
|
{},
|
|
567
612
|
async () => (await me()).api.claimDaily(),
|
|
568
613
|
WRITE,
|
|
@@ -1667,7 +1712,8 @@ import fs4 from "node:fs";
|
|
|
1667
1712
|
import path4 from "node:path";
|
|
1668
1713
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1669
1714
|
import { z as z7 } from "zod";
|
|
1670
|
-
import {
|
|
1715
|
+
import { spawn } from "node:child_process";
|
|
1716
|
+
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE, getUiCapability } from "@modelcontextprotocol/ext-apps/server";
|
|
1671
1717
|
var GAME = (process.env.PARALITH_GAME_URL || "https://game.paralithmarkets.com").replace(/\/$/, "");
|
|
1672
1718
|
var TRADE = (process.env.PARALITH_TRADE_URL || "https://trade.paralithmarkets.com").replace(/\/$/, "");
|
|
1673
1719
|
var URI = "ui://paralith/view";
|
|
@@ -1700,6 +1746,16 @@ async function ownAddress() {
|
|
|
1700
1746
|
const { wallets } = await runtime();
|
|
1701
1747
|
return wallets?.ao.address;
|
|
1702
1748
|
}
|
|
1749
|
+
function openInBrowser(url) {
|
|
1750
|
+
const [cmd, args] = process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url]] : process.platform === "darwin" ? ["open", [url]] : ["xdg-open", [url]];
|
|
1751
|
+
try {
|
|
1752
|
+
spawn(cmd, args, { detached: true, stdio: "ignore" }).on("error", () => {
|
|
1753
|
+
}).unref();
|
|
1754
|
+
return true;
|
|
1755
|
+
} catch {
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1703
1759
|
function registerShow(server) {
|
|
1704
1760
|
const csp = { frameDomains: [GAME, TRADE] };
|
|
1705
1761
|
registerAppResource(
|
|
@@ -1710,7 +1766,7 @@ function registerShow(server) {
|
|
|
1710
1766
|
async () => ({ contents: [{ uri: URI, mimeType: RESOURCE_MIME_TYPE, text: viewHtml(), _meta: { ui: { csp } } }] })
|
|
1711
1767
|
);
|
|
1712
1768
|
registerAppTool(server, "show", {
|
|
1713
|
-
description: "Show something with the game's and exchange's own visuals, live: battle (follows a player's arena fights, animated), companion (card), hunt, market (order book and chart), vault, position, bridge (transfers).
|
|
1769
|
+
description: "Show something with the game's and exchange's own visuals, live: battle (follows a player's arena fights, animated), companion (card), hunt, market (order book and chart), vault, position, bridge (transfers). Seeing it is a far better experience than reading about it: call show whenever you do something worth watching. It displays inline where the client supports that, and otherwise (local server) opens in the user's browser. Address defaults to yours.",
|
|
1714
1770
|
inputSchema: {
|
|
1715
1771
|
what: z7.enum(Object.keys(VIEWS)),
|
|
1716
1772
|
address: z7.string().optional().describe("AO address; omit for yours."),
|
|
@@ -1721,14 +1777,19 @@ function registerShow(server) {
|
|
|
1721
1777
|
market: z7.string().optional().describe("market/vault: the market, as exchange_markets lists it."),
|
|
1722
1778
|
vault: z7.enum(["amm", "active", "grid"]).optional(),
|
|
1723
1779
|
chain: z7.enum(["base", "solana", "sui"]).optional().describe("bridge: with tx, one transfer."),
|
|
1724
|
-
tx: z7.string().optional()
|
|
1780
|
+
tx: z7.string().optional(),
|
|
1781
|
+
open: z7.boolean().optional().describe("Open in the user's browser. Default: only when this client cannot display it inline.")
|
|
1725
1782
|
},
|
|
1726
1783
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1727
1784
|
_meta: { ui: { resourceUri: URI } }
|
|
1728
1785
|
}, async (args) => {
|
|
1729
1786
|
try {
|
|
1730
1787
|
const view = VIEWS[args.what]({ ...args, address: args.address ?? await ownAddress() });
|
|
1731
|
-
|
|
1788
|
+
const inline = !!getUiCapability(server.server.getClientCapabilities());
|
|
1789
|
+
const opened = !READ_ONLY && (args.open ?? !inline) && openInBrowser(view);
|
|
1790
|
+
const where = inline ? "Displayed inline." : opened ? "Opened in the user's browser." : "Give the user this link.";
|
|
1791
|
+
return { structuredContent: { what: args.what, view }, content: [{ type: "text", text: `${args.what}: ${view}
|
|
1792
|
+
${where}` }] };
|
|
1732
1793
|
} catch (error) {
|
|
1733
1794
|
return { isError: true, content: [{ type: "text", text: error.message }] };
|
|
1734
1795
|
}
|
|
@@ -1847,9 +1908,26 @@ Vaults (pooled liquidity, one amm/active/grid per market): vault_list, vault_pos
|
|
|
1847
1908
|
Rune: rune_move withdraw (game -> token) / deposit (token -> game). Bridge: bridge_balances, bridge_faucet, bridge_deposit, bridge_redeem.
|
|
1848
1909
|
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.
|
|
1849
1910
|
|
|
1911
|
+
HOW RESOURCES FLOW. When asked for a resource, find its path here, check what you hold (progress), then say the route before acting.
|
|
1912
|
+
- Gold (in-game only, never leaves the game). Earn: companion play/quest/claim (capped at 60 Gold per 20 h), arena bot wins,
|
|
1913
|
+
selling berries/Scrolls/Rune to the shop (game_shop sell) or on the game venue. Spend: arena stakes, shop buys, game-venue buys.
|
|
1914
|
+
- Berries and Scrolls. Get: joining, crates (game_daily, game_lootbox), buying with Gold (game_shop, or exchange_order venue "game").
|
|
1915
|
+
Use: feed the companion, hunt escrow (2 of each berry), arena boosts; a Scroll plus 1-3 Rune for a hunt capture.
|
|
1916
|
+
- Rune exists twice: in-game Rune and the TEST-RUNE wallet token; rune_move converts 1:1 either way.
|
|
1917
|
+
Get Rune: (1) the shop, only if game_shop quote shows an ask (it often only bids); (2) sell a companion on companion_market;
|
|
1918
|
+
(3) the token route, which always works: element_claim (free daily, 1-10 of one element) -> exchange_order venue "token"
|
|
1919
|
+
sell that element for TEST-RUNE -> rune_move deposit. Public TEST accounts accrue no Rune from game_daily (pass holders only).
|
|
1920
|
+
Spend in-game Rune: game_level_up, hunt capture, companion_market buys. TEST-RUNE: token-venue buys, vaults, dao_stake.
|
|
1921
|
+
- Element tokens (TEST-EARTH/AIR/FIRE/WATER): element_claim daily; trade against TEST-RUNE on the token venue; vault liquidity.
|
|
1922
|
+
- PUSD: bridge in TEST-USDC from Base, Solana or Sui (needs that chain's gas, which the user funds; bridge_faucet gives TEST-USDC).
|
|
1923
|
+
No PUSD market is listed yet. Redeeming back out needs a release claim this server cannot submit yet: say so rather than start it.
|
|
1924
|
+
- Vaults: deposit both sides of a market to earn from its strategy; withdraw with vault_shares.
|
|
1925
|
+
|
|
1850
1926
|
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.
|
|
1851
1927
|
|
|
1852
|
-
|
|
1928
|
+
SHOW IT. Watching beats reading: call show for anything worth seeing (a fight as it happens, the companion after a level-up, the book
|
|
1929
|
+
you are trading, a vault, a bridge transfer). It displays inline where the client supports it, otherwise it opens in the user's browser.
|
|
1930
|
+
Show once per thing, not once per round.
|
|
1853
1931
|
|
|
1854
1932
|
Rules: if a tool says a write WAS accepted but unconfirmed, never resend it; re-read state instead.
|
|
1855
1933
|
A refusal ({"error": ...}) costs nothing. Use game_catalog for exact costs and move stats; docs at ${DOCS}/llms-full.txt.`;
|
|
@@ -1857,7 +1935,7 @@ var READ_ONLY_NOTE = `This endpoint is READ-ONLY: it explains the protocol and r
|
|
|
1857
1935
|
To play, trade or bridge, run the local server with a wallet phrase: ${DOCS}/ai/mcp`;
|
|
1858
1936
|
function buildServer() {
|
|
1859
1937
|
const server = new McpServer(
|
|
1860
|
-
{ name: "paralith", version:
|
|
1938
|
+
{ name: "paralith", version: VERSION },
|
|
1861
1939
|
{ instructions: READ_ONLY ? `${READ_ONLY_NOTE}
|
|
1862
1940
|
|
|
1863
1941
|
${INSTRUCTIONS}` : INSTRUCTIONS }
|
package/dist/server.mjs
CHANGED
|
@@ -511,17 +511,65 @@ var init_runtime = __esm({
|
|
|
511
511
|
}
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
+
// src/update.mjs
|
|
515
|
+
function check(now) {
|
|
516
|
+
checkedAt = now;
|
|
517
|
+
fetch("https://registry.npmjs.org/paralith-mcp/latest", { signal: AbortSignal.timeout(1e4) }).then((r) => r.ok ? r.json() : null).then((j) => {
|
|
518
|
+
if (j?.version) latest = j.version;
|
|
519
|
+
}, () => {
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
function updateNote(now = Date.now()) {
|
|
523
|
+
if (now - checkedAt > CHECK_MS) check(now);
|
|
524
|
+
if (!latest || !newer(latest, VERSION) || now - notedAt < NOTE_MS) return null;
|
|
525
|
+
notedAt = now;
|
|
526
|
+
return `paralith-mcp ${latest} is out (this is ${VERSION}). Tell the user to restart this app to get it.`;
|
|
527
|
+
}
|
|
528
|
+
var VERSION, CHECK_MS, NOTE_MS, latest, checkedAt, notedAt, newer;
|
|
529
|
+
var init_update = __esm({
|
|
530
|
+
"src/update.mjs"() {
|
|
531
|
+
"use strict";
|
|
532
|
+
VERSION = "0.3.2";
|
|
533
|
+
CHECK_MS = 6 * 36e5;
|
|
534
|
+
NOTE_MS = 36e5;
|
|
535
|
+
latest = null;
|
|
536
|
+
checkedAt = 0;
|
|
537
|
+
notedAt = 0;
|
|
538
|
+
newer = (a, b) => {
|
|
539
|
+
const [x, y] = [a, b].map((v) => v.split(".").map(Number));
|
|
540
|
+
for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] > y[i];
|
|
541
|
+
return false;
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
514
546
|
// src/tool.mjs
|
|
515
547
|
import { z } from "zod";
|
|
548
|
+
async function migrationRefusal(read = readKey, now = Date.now()) {
|
|
549
|
+
if (!migrationSeen || now - migrationSeen.at > 15e3) {
|
|
550
|
+
migrationSeen = { at: now, value: await read("game", "migration").catch(() => null) };
|
|
551
|
+
}
|
|
552
|
+
const m = migrationSeen.value;
|
|
553
|
+
if (!m || typeof m !== "object" || m.phase === "live") return null;
|
|
554
|
+
if (m.phase === "retired") {
|
|
555
|
+
return `Paralith has moved to new processes (the game is now ${m.successor}). Nothing was sent. Update paralith-mcp to its latest version to use them.`;
|
|
556
|
+
}
|
|
557
|
+
return "A migration is in progress: Paralith is paused while every balance moves to new processes. Nothing was sent, and nothing is lost. Reads still work; try writes again later.";
|
|
558
|
+
}
|
|
516
559
|
function tool(server, name, description, inputSchema, run2, annotations = {}, view = null) {
|
|
517
560
|
if (READ_ONLY && annotations !== READ) return;
|
|
518
561
|
const schema = view ? { ...inputSchema, full: z.boolean().optional().describe("Return the raw record instead of the compact view.") } : inputSchema;
|
|
519
562
|
server.registerTool(name, { description, inputSchema: schema, annotations }, async (args) => {
|
|
520
563
|
try {
|
|
564
|
+
if (annotations === WRITE) {
|
|
565
|
+
const refusal = await migrationRefusal();
|
|
566
|
+
if (refusal) return { isError: true, content: [{ type: "text", text: refusal }] };
|
|
567
|
+
}
|
|
521
568
|
const raw = await run2(args ?? {});
|
|
522
569
|
const value = view && !args?.full ? await view(raw) : raw;
|
|
523
570
|
const text = typeof value === "string" ? value : JSON.stringify(value, bigints, 2);
|
|
524
|
-
|
|
571
|
+
const note = READ_ONLY ? null : updateNote();
|
|
572
|
+
return { content: [{ type: "text", text: text ?? "null" }, ...note ? [{ type: "text", text: note }] : []] };
|
|
525
573
|
} catch (error) {
|
|
526
574
|
return { isError: true, content: [{ type: "text", text: explain(error) }] };
|
|
527
575
|
}
|
|
@@ -537,11 +585,13 @@ The message WAS accepted (slot ${error?.slot ?? "?"}); its result could not be c
|
|
|
537
585
|
}
|
|
538
586
|
return message;
|
|
539
587
|
}
|
|
540
|
-
var bigints, READ, OWN, WRITE;
|
|
588
|
+
var migrationSeen, bigints, READ, OWN, WRITE;
|
|
541
589
|
var init_tool = __esm({
|
|
542
590
|
"src/tool.mjs"() {
|
|
543
591
|
"use strict";
|
|
544
592
|
init_runtime();
|
|
593
|
+
init_update();
|
|
594
|
+
migrationSeen = null;
|
|
545
595
|
bigints = (_k, v) => typeof v === "bigint" ? v.toString() : v;
|
|
546
596
|
READ = { readOnlyHint: true, openWorldHint: true };
|
|
547
597
|
OWN = { readOnlyHint: true, openWorldHint: true };
|
|
@@ -780,7 +830,7 @@ function registerGame(server) {
|
|
|
780
830
|
tool(
|
|
781
831
|
server,
|
|
782
832
|
"game_daily",
|
|
783
|
-
"Claim the daily crate and Rune. Once per UTC day.",
|
|
833
|
+
"Claim the daily crate (and accrued Rune, pass holders only). Once per UTC day.",
|
|
784
834
|
{},
|
|
785
835
|
async () => (await me()).api.claimDaily(),
|
|
786
836
|
WRITE,
|
|
@@ -1928,7 +1978,8 @@ import fs5 from "node:fs";
|
|
|
1928
1978
|
import path5 from "node:path";
|
|
1929
1979
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1930
1980
|
import { z as z7 } from "zod";
|
|
1931
|
-
import {
|
|
1981
|
+
import { spawn } from "node:child_process";
|
|
1982
|
+
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE, getUiCapability } from "@modelcontextprotocol/ext-apps/server";
|
|
1932
1983
|
function viewHtml() {
|
|
1933
1984
|
for (const file of [path5.join(HERE2, "view.html"), path5.join(HERE2, "..", "dist", "view.html")]) {
|
|
1934
1985
|
if (fs5.existsSync(file)) return fs5.readFileSync(file, "utf8");
|
|
@@ -1944,6 +1995,16 @@ async function ownAddress() {
|
|
|
1944
1995
|
const { wallets } = await runtime();
|
|
1945
1996
|
return wallets?.ao.address;
|
|
1946
1997
|
}
|
|
1998
|
+
function openInBrowser(url) {
|
|
1999
|
+
const [cmd, args] = process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url]] : process.platform === "darwin" ? ["open", [url]] : ["xdg-open", [url]];
|
|
2000
|
+
try {
|
|
2001
|
+
spawn(cmd, args, { detached: true, stdio: "ignore" }).on("error", () => {
|
|
2002
|
+
}).unref();
|
|
2003
|
+
return true;
|
|
2004
|
+
} catch {
|
|
2005
|
+
return false;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
1947
2008
|
function registerShow(server) {
|
|
1948
2009
|
const csp = { frameDomains: [GAME, TRADE] };
|
|
1949
2010
|
registerAppResource(
|
|
@@ -1954,7 +2015,7 @@ function registerShow(server) {
|
|
|
1954
2015
|
async () => ({ contents: [{ uri: URI, mimeType: RESOURCE_MIME_TYPE, text: viewHtml(), _meta: { ui: { csp } } }] })
|
|
1955
2016
|
);
|
|
1956
2017
|
registerAppTool(server, "show", {
|
|
1957
|
-
description: "Show something with the game's and exchange's own visuals, live: battle (follows a player's arena fights, animated), companion (card), hunt, market (order book and chart), vault, position, bridge (transfers).
|
|
2018
|
+
description: "Show something with the game's and exchange's own visuals, live: battle (follows a player's arena fights, animated), companion (card), hunt, market (order book and chart), vault, position, bridge (transfers). Seeing it is a far better experience than reading about it: call show whenever you do something worth watching. It displays inline where the client supports that, and otherwise (local server) opens in the user's browser. Address defaults to yours.",
|
|
1958
2019
|
inputSchema: {
|
|
1959
2020
|
what: z7.enum(Object.keys(VIEWS)),
|
|
1960
2021
|
address: z7.string().optional().describe("AO address; omit for yours."),
|
|
@@ -1965,14 +2026,19 @@ function registerShow(server) {
|
|
|
1965
2026
|
market: z7.string().optional().describe("market/vault: the market, as exchange_markets lists it."),
|
|
1966
2027
|
vault: z7.enum(["amm", "active", "grid"]).optional(),
|
|
1967
2028
|
chain: z7.enum(["base", "solana", "sui"]).optional().describe("bridge: with tx, one transfer."),
|
|
1968
|
-
tx: z7.string().optional()
|
|
2029
|
+
tx: z7.string().optional(),
|
|
2030
|
+
open: z7.boolean().optional().describe("Open in the user's browser. Default: only when this client cannot display it inline.")
|
|
1969
2031
|
},
|
|
1970
2032
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1971
2033
|
_meta: { ui: { resourceUri: URI } }
|
|
1972
2034
|
}, async (args) => {
|
|
1973
2035
|
try {
|
|
1974
2036
|
const view = VIEWS[args.what]({ ...args, address: args.address ?? await ownAddress() });
|
|
1975
|
-
|
|
2037
|
+
const inline = !!getUiCapability(server.server.getClientCapabilities());
|
|
2038
|
+
const opened = !READ_ONLY && (args.open ?? !inline) && openInBrowser(view);
|
|
2039
|
+
const where = inline ? "Displayed inline." : opened ? "Opened in the user's browser." : "Give the user this link.";
|
|
2040
|
+
return { structuredContent: { what: args.what, view }, content: [{ type: "text", text: `${args.what}: ${view}
|
|
2041
|
+
${where}` }] };
|
|
1976
2042
|
} catch (error) {
|
|
1977
2043
|
return { isError: true, content: [{ type: "text", text: error.message }] };
|
|
1978
2044
|
}
|
|
@@ -2120,7 +2186,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2120
2186
|
import { z as z9 } from "zod";
|
|
2121
2187
|
function buildServer() {
|
|
2122
2188
|
const server = new McpServer(
|
|
2123
|
-
{ name: "paralith", version:
|
|
2189
|
+
{ name: "paralith", version: VERSION },
|
|
2124
2190
|
{ instructions: READ_ONLY ? `${READ_ONLY_NOTE}
|
|
2125
2191
|
|
|
2126
2192
|
${INSTRUCTIONS}` : INSTRUCTIONS }
|
|
@@ -2210,6 +2276,7 @@ var init_build = __esm({
|
|
|
2210
2276
|
init_vaults();
|
|
2211
2277
|
init_show();
|
|
2212
2278
|
init_progress();
|
|
2279
|
+
init_update();
|
|
2213
2280
|
DOCS = process.env.PARALITH_DOCS_URL || "https://docs.paralithmarkets.com";
|
|
2214
2281
|
INSTRUCTIONS = `Paralith on AO (HyperBEAM): Rune Realm (a companion game), two order books, and the PUSD bridge.
|
|
2215
2282
|
Everything is TEST-prefixed while unreleased. Reads are free; every write is a signed message (a few seconds round trip, longer under load).
|
|
@@ -2225,9 +2292,26 @@ Vaults (pooled liquidity, one amm/active/grid per market): vault_list, vault_pos
|
|
|
2225
2292
|
Rune: rune_move withdraw (game -> token) / deposit (token -> game). Bridge: bridge_balances, bridge_faucet, bridge_deposit, bridge_redeem.
|
|
2226
2293
|
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.
|
|
2227
2294
|
|
|
2295
|
+
HOW RESOURCES FLOW. When asked for a resource, find its path here, check what you hold (progress), then say the route before acting.
|
|
2296
|
+
- Gold (in-game only, never leaves the game). Earn: companion play/quest/claim (capped at 60 Gold per 20 h), arena bot wins,
|
|
2297
|
+
selling berries/Scrolls/Rune to the shop (game_shop sell) or on the game venue. Spend: arena stakes, shop buys, game-venue buys.
|
|
2298
|
+
- Berries and Scrolls. Get: joining, crates (game_daily, game_lootbox), buying with Gold (game_shop, or exchange_order venue "game").
|
|
2299
|
+
Use: feed the companion, hunt escrow (2 of each berry), arena boosts; a Scroll plus 1-3 Rune for a hunt capture.
|
|
2300
|
+
- Rune exists twice: in-game Rune and the TEST-RUNE wallet token; rune_move converts 1:1 either way.
|
|
2301
|
+
Get Rune: (1) the shop, only if game_shop quote shows an ask (it often only bids); (2) sell a companion on companion_market;
|
|
2302
|
+
(3) the token route, which always works: element_claim (free daily, 1-10 of one element) -> exchange_order venue "token"
|
|
2303
|
+
sell that element for TEST-RUNE -> rune_move deposit. Public TEST accounts accrue no Rune from game_daily (pass holders only).
|
|
2304
|
+
Spend in-game Rune: game_level_up, hunt capture, companion_market buys. TEST-RUNE: token-venue buys, vaults, dao_stake.
|
|
2305
|
+
- Element tokens (TEST-EARTH/AIR/FIRE/WATER): element_claim daily; trade against TEST-RUNE on the token venue; vault liquidity.
|
|
2306
|
+
- PUSD: bridge in TEST-USDC from Base, Solana or Sui (needs that chain's gas, which the user funds; bridge_faucet gives TEST-USDC).
|
|
2307
|
+
No PUSD market is listed yet. Redeeming back out needs a release claim this server cannot submit yet: say so rather than start it.
|
|
2308
|
+
- Vaults: deposit both sides of a market to earn from its strategy; withdraw with vault_shares.
|
|
2309
|
+
|
|
2228
2310
|
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.
|
|
2229
2311
|
|
|
2230
|
-
|
|
2312
|
+
SHOW IT. Watching beats reading: call show for anything worth seeing (a fight as it happens, the companion after a level-up, the book
|
|
2313
|
+
you are trading, a vault, a bridge transfer). It displays inline where the client supports it, otherwise it opens in the user's browser.
|
|
2314
|
+
Show once per thing, not once per round.
|
|
2231
2315
|
|
|
2232
2316
|
Rules: if a tool says a write WAS accepted but unconfirmed, never resend it; re-read state instead.
|
|
2233
2317
|
A refusal ({"error": ...}) costs nothing. Use game_catalog for exact costs and move stats; docs at ${DOCS}/llms-full.txt.`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paralith-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "MCP server for Paralith on AO: an AI with one 24-word phrase plays Rune Realm, trades and bridges PUSD (TEST deployment).",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://docs.paralithmarkets.com/ai/mcp",
|