@zypheragent/mcp 0.4.0 → 0.5.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 +9 -5
- package/dist/index.js +69 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ Generic stdio client, with optional environment:
|
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
With a valid token the server registers
|
|
66
|
+
With a valid token the server registers eleven more tools (28 in total) and its ready line says `read + EXECUTION`. A malformed token prints a clear error on stderr and execution stays disabled; the 17 read tools keep working.
|
|
67
67
|
|
|
68
68
|
| Tool | What it does | Arguments |
|
|
69
69
|
| --- | --- | --- |
|
|
@@ -72,16 +72,18 @@ With a valid token the server registers nine more tools (24 in total) and its re
|
|
|
72
72
|
| `agent_elysium_swap` | Swap on Elysium 99901 (native HYPE <-> a Boxa-indexed token) from the Agent Wallet. | `tokenIn`, `tokenOut` (HYPE on one side; symbol or 0x address), `amountIn`, optional `slippageBps` |
|
|
73
73
|
| `agent_elysium_launch` | **Launch a token on Elysium** through Boxa's V3 launcher from the Agent Wallet (1B supply in locked liquidity, no creation fee). | `name`, `symbol`, optional `description`, `image`/`website`/`twitter`/`telegram` (https URLs), `allocation` (`balanced`, `creator`, `holders`, `buyback`, `liquidity` or four basis-point shares summing to 10000), `antiSnipe`, `firstBuyHype` |
|
|
74
74
|
| `agent_bridge_elysium` | Move native HYPE HyperEVM <-> Elysium for the Agent Wallet (fund it before an Elysium swap or launch). | `direction` (`deposit`\|`withdraw`), `amount` |
|
|
75
|
+
| `agent_bridge` | Bridge with Relay between chains (name or id, tokens by symbol/address) from the Agent Wallet. Recipient: the wallet itself or an address on your send allow-list. | `originChain`, `destinationChain`, `amount`, optional `originToken`, `destinationToken`, `recipient` |
|
|
76
|
+
| `upload_token_image` | Upload a token image (PNG/JPEG/GIF/WebP, up to 4 MB, base64 or data URL) and get an https URL for `agent_elysium_launch`. No funds, API token not sent. | `imageBase64` |
|
|
75
77
|
| `agent_perp_order` | Open/add a Hyperliquid perp position. | `coin` (`BTC`, `xyz:NVDA`), `side` long\|short, `notionalUsd`, `leverage`, optional `tpPrice`, `slPrice`, `reduceOnly` |
|
|
76
78
|
| `agent_close` | Close a perp position (all or a percentage). | `coin`, optional `fractionPct` (0-100) |
|
|
77
79
|
| `agent_send` | Send funds from the Agent Wallet to an external 0x address. | `asset`, `amount`, `to` (0x address) |
|
|
78
80
|
| `agent_transfer_out` | Move funds from the Agent Wallet back to your own main wallet. | `asset`, `amount` |
|
|
79
81
|
|
|
80
|
-
**These tools move real funds on mainnet.** Every call executes immediately from your Agent Wallet, inside the caps set by you / the operator in the app. There is **no confirmation step** in the MCP, so the assistant is told to ask you first; do not auto-approve these tools in your client. No tool accepts a wallet, owner, URL or path argument: the package can only call the
|
|
82
|
+
**These tools move real funds on mainnet.** Every call executes immediately from your Agent Wallet, inside the caps set by you / the operator in the app. There is **no confirmation step** in the MCP, so the assistant is told to ask you first; do not auto-approve these tools in your client. No tool accepts a wallet, owner, URL or path argument: the package can only call the ten fixed paths `/api/agent-api/{status,swap,elysium-swap,elysium-launch,bridge-boxa,bridge,perp-order,close,send,transfer-out}` (plus the public image upload route of the same host for `upload_token_image`, which never receives the token) under `ZYPHER_API_URL`.
|
|
81
83
|
|
|
82
84
|
Each write call carries a fresh random `Idempotency-Key`. Timeouts are 15 s (45 s for swaps); redirects are refused and responses over 100 KB are refused. After a timeout or a 5xx on a write, the outcome is unknown: call `agent_status` before retrying.
|
|
83
85
|
|
|
84
|
-
## Tools (
|
|
86
|
+
## Tools (17 read tools, always on)
|
|
85
87
|
|
|
86
88
|
| Tool | What it does |
|
|
87
89
|
| --- | --- |
|
|
@@ -90,6 +92,8 @@ Each write call carries a fresh random `Idempotency-Key`. Timeouts are 15 s (45
|
|
|
90
92
|
| `get_strong_volume` | Perp tickers with the highest 24h volume, with volume/OI ratio and price change. |
|
|
91
93
|
| `get_new_pairs` | Newest token launches on Elysium 99901 (all launchpads), newest first. Elysium only; `chain=hyperevm` returns an explicit error. |
|
|
92
94
|
| `get_elysium_market` | The Elysium market / launchpad feed (like the app's Market and Launch tabs): sort `newest`, `fdv` (top), `volume` (trending), `change` (gainers), `trades`, `holders`; filter by launchpad (`boxa`, `kleos`, `ascend`, `montra`, `volta`, `elyspump`, `uniswap`, `stockium`, `stocks`...), search `q`, `tradable`. Read from the Zypher public API. |
|
|
95
|
+
| `get_elysium_activity` | Recent swaps (or transfers) of an Elysium token, newest first, from chain logs (side, amounts, wallet, block); page backwards with `before`. Times are approximate. |
|
|
96
|
+
| `get_elysium_holders` | Largest holders of an Elysium token seen in recent activity (not a full ranking) plus the index holder count. |
|
|
93
97
|
| `get_elysium_token` | One Elysium token by address: launchpad, pool, price, FDV, 24h change/volume, holders, tradable flag. |
|
|
94
98
|
| `analyze_token_health` | Bytecode/ABI check of a token contract (mint, pause, blacklist, owner) with a score and reasons. A heuristic, not an audit. |
|
|
95
99
|
| `get_social_info` | Recent tweets about a ticker. Needs your own `X_BEARER_TOKEN`; without it the tool returns a clear error. |
|
|
@@ -110,7 +114,7 @@ All tool output is JSON text. Text that comes from third parties (token names, t
|
|
|
110
114
|
| `ZYPHER_NETWORK` | `mainnet` | Hyperliquid network for perp reads (`mainnet` is the default and the product's only network). |
|
|
111
115
|
| `ZYPHER_ADDRESS` | unset | Public `0x...` address used by `get_portfolio` / `get_hl_account` when no `address` argument is passed. Never put a private key here. |
|
|
112
116
|
| `X_BEARER_TOKEN` | unset | Your X API bearer token, only for `get_social_info`. |
|
|
113
|
-
| `ZYPHER_API_TOKEN` | unset | Agent Wallet API token (`zat_` + 40 lowercase hex). Enables the
|
|
117
|
+
| `ZYPHER_API_TOKEN` | unset | Agent Wallet API token (`zat_` + 40 lowercase hex). Enables the ten `agent_*` tools and `upload_token_image`. Sent only as `Authorization: Bearer` to `ZYPHER_API_URL`; never logged. |
|
|
114
118
|
| `ZYPHER_API_URL` | `https://zypheragent.com/agent` | Base URL of the Zypher Agent API. Must be https (plain http only for `localhost` / `127.0.0.1`). A different host prints a one-line stderr warning that the token will be sent there. |
|
|
115
119
|
| `ELYSIUM_RPC` | `https://rpc-live.boxa.club` | Override the Elysium (99901) RPC URL. |
|
|
116
120
|
| `HYPEREVM_RPC` | public HyperEVM RPC | Override the HyperEVM (999) RPC URL. |
|
|
@@ -119,7 +123,7 @@ No other variables are read.
|
|
|
119
123
|
|
|
120
124
|
## Network behaviour
|
|
121
125
|
|
|
122
|
-
- Without a token only public, unauthenticated data endpoints are contacted. With `ZYPHER_API_TOKEN` it additionally talks to `ZYPHER_API_URL` (default `https://zypheragent.com/agent`), only on the
|
|
126
|
+
- Without a token only public, unauthenticated data endpoints are contacted. With `ZYPHER_API_TOKEN` it additionally talks to `ZYPHER_API_URL` (default `https://zypheragent.com/agent`), only on the ten fixed `/api/agent-api/*` paths. Read tools contact: the Hyperliquid info API (`api.hyperliquid.xyz`), the public HyperEVM RPC (`rpc.hyperliquid.xyz/evm`) and the Elysium 99901 RPC (`rpc-live.boxa.club`, run by Boxa) and, for the Elysium market tools, the public Zypher API (`zypheragent.com/agent`). `get_social_info` contacts `api.x.com` only with your own token.
|
|
123
127
|
- Requests carry the header `User-Agent: zypher-mcp/<version>`.
|
|
124
128
|
- No telemetry, no analytics, no phone-home. The package writes nothing to disk.
|
|
125
129
|
- Default is **mainnet** (real markets): Hyperliquid mainnet, HyperEVM 999 and Elysium 99901. **Elysium 99901 is a community-run chain served by Boxa (rpc-live.boxa.club), not the official Kinetiq mainnet**; `get_launch_info` checks that the chain id and the pinned contract code hashes still match and says so when they do not. Its RPC and contracts are third-party; a lying or lagging RPC cannot be detected from here.
|
package/dist/index.js
CHANGED
|
@@ -574,6 +574,42 @@ async function elysiumToken(address) {
|
|
|
574
574
|
const px = typeof j.hypeUsd === "number" ? j.hypeUsd : null;
|
|
575
575
|
return { network: "Elysium 99901", hypeUsd: px, token: row(j.token ?? j, px), detail: j.info ?? null };
|
|
576
576
|
}
|
|
577
|
+
var rowAct = (r) => ({ ...r });
|
|
578
|
+
async function elysiumActivity(address, limit, before) {
|
|
579
|
+
const j = await getJson("/api/market/elysium/activity", { address, limit, before });
|
|
580
|
+
return { network: "Elysium 99901", token: j.token ?? address, source: j.source, rows: (j.rows ?? []).slice(0, limit).map(rowAct), nextBefore: j.nextBefore ?? null, approxTime: j.approxTime ?? true, note: j.note ?? "Times are approximate (block based). Page backwards with before=nextBefore." };
|
|
581
|
+
}
|
|
582
|
+
async function elysiumHolders(address) {
|
|
583
|
+
const j = await getJson("/api/market/elysium/holders", { address });
|
|
584
|
+
return { network: "Elysium 99901", token: address, holdersTotal: j.holdersTotal ?? null, coverage: j.coverage ?? "recent activity only", top: (j.top ?? []).slice(0, 25), note: j.note ?? null };
|
|
585
|
+
}
|
|
586
|
+
var IMAGE_MAX_BYTES = 4 * 1024 * 1024;
|
|
587
|
+
function sniffImage(b) {
|
|
588
|
+
const at = (s, o = 0) => s.split("").every((c, i) => b[o + i] === c.charCodeAt(0));
|
|
589
|
+
if (b.length > 8 && b[0] === 137 && at("PNG", 1) && b[4] === 13 && b[5] === 10 && b[6] === 26 && b[7] === 10) return "image/png";
|
|
590
|
+
if (b.length > 3 && b[0] === 255 && b[1] === 216 && b[2] === 255) return "image/jpeg";
|
|
591
|
+
if (b.length > 12 && at("RIFF") && at("WEBP", 8)) return "image/webp";
|
|
592
|
+
if (b.length > 6 && at("GIF8") && (b[4] === 55 || b[4] === 57) && b[5] === 97) return "image/gif";
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
async function uploadTokenImage(imageBase64) {
|
|
596
|
+
const raw = imageBase64.trim().replace(/^data:[^,]*;base64,/i, "").replace(/\s+/g, "");
|
|
597
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(raw) || raw.length < 16) throw new Error("imageBase64 must be a base64 encoded PNG, JPEG, GIF or WebP image.");
|
|
598
|
+
if (raw.length > Math.ceil(IMAGE_MAX_BYTES / 3) * 4 + 8) throw new Error("That image is too large. The limit is 4 MB.");
|
|
599
|
+
const bytes = Buffer.from(raw, "base64");
|
|
600
|
+
if (bytes.length > IMAGE_MAX_BYTES) throw new Error("That image is too large. The limit is 4 MB.");
|
|
601
|
+
const type = sniffImage(bytes);
|
|
602
|
+
if (!type) throw new Error("The data is not a PNG, JPEG, GIF or WebP image (checked by its first bytes).");
|
|
603
|
+
const r = await fetch(BASE() + "/api/launch-mainnet/upload", { method: "POST", headers: { "content-type": type, accept: "application/json" }, body: new Uint8Array(bytes), redirect: "error", signal: AbortSignal.timeout(3e4) });
|
|
604
|
+
const text = await r.text();
|
|
605
|
+
let j = null;
|
|
606
|
+
try {
|
|
607
|
+
j = JSON.parse(text);
|
|
608
|
+
} catch {
|
|
609
|
+
}
|
|
610
|
+
if (!r.ok || !j?.ok || typeof j.url !== "string" || !/^https:\/\//.test(j.url)) throw new Error(`Image upload refused (HTTP ${r.status}): ${cleanLabel(String(j?.error ?? "unexpected answer"), 160)}`);
|
|
611
|
+
return { url: j.url, type, bytes: bytes.length, next: "Pass this url as `image` to agent_elysium_launch." };
|
|
612
|
+
}
|
|
577
613
|
|
|
578
614
|
// src/market/reads.ts
|
|
579
615
|
import { formatUnits as formatUnits3, getAddress as getAddress4, isAddress as isAddress2, parseUnits } from "viem";
|
|
@@ -994,6 +1030,18 @@ var tools = [
|
|
|
994
1030
|
shape: { address: evmAddr },
|
|
995
1031
|
handler: async (a) => elysiumToken(a.address)
|
|
996
1032
|
},
|
|
1033
|
+
{
|
|
1034
|
+
name: "get_elysium_activity",
|
|
1035
|
+
description: "Recent swaps (or transfers) of an Elysium 99901 token, newest first, read from chain logs: side, amounts, wallet, block. Times are approximate. Page backwards with before = nextBefore of the previous answer.",
|
|
1036
|
+
shape: { address: evmAddr, limit: z.number().int().min(1).max(60).default(30), before: z.number().int().min(0).max(1e9).optional() },
|
|
1037
|
+
handler: async (a) => elysiumActivity(a.address, a.limit, a.before)
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
name: "get_elysium_holders",
|
|
1041
|
+
description: "Largest holders of an Elysium 99901 token SEEN IN RECENT ACTIVITY (not a full ranking), plus the total holder count from the index.",
|
|
1042
|
+
shape: { address: evmAddr },
|
|
1043
|
+
handler: async (a) => elysiumHolders(a.address)
|
|
1044
|
+
},
|
|
997
1045
|
{
|
|
998
1046
|
name: "analyze_token_health",
|
|
999
1047
|
description: "Check a token contract (mint/pause/blacklist/owner) on HyperEVM mainnet (default) or Elysium 99901 and give a score with reasons. Bytecode heuristic, not a safety guarantee.",
|
|
@@ -1076,7 +1124,7 @@ var MAX_RESPONSE_BYTES = 100 * 1024;
|
|
|
1076
1124
|
var TIMEOUT_MS = 15e3;
|
|
1077
1125
|
var SWAP_TIMEOUT_MS = 45e3;
|
|
1078
1126
|
var DEFAULT_HOST = "zypheragent.com";
|
|
1079
|
-
var ALLOWED_PATHS = ["/api/agent-api/status", "/api/agent-api/swap", "/api/agent-api/elysium-swap", "/api/agent-api/elysium-launch", "/api/agent-api/bridge-boxa", "/api/agent-api/perp-order", "/api/agent-api/close", "/api/agent-api/send", "/api/agent-api/transfer-out"];
|
|
1127
|
+
var ALLOWED_PATHS = ["/api/agent-api/status", "/api/agent-api/swap", "/api/agent-api/elysium-swap", "/api/agent-api/elysium-launch", "/api/agent-api/bridge-boxa", "/api/agent-api/bridge", "/api/agent-api/perp-order", "/api/agent-api/close", "/api/agent-api/send", "/api/agent-api/transfer-out"];
|
|
1080
1128
|
function loadExecConfig(e2 = process.env) {
|
|
1081
1129
|
const token = e2.ZYPHER_API_TOKEN?.trim();
|
|
1082
1130
|
if (!token) return { enabled: false };
|
|
@@ -1114,6 +1162,7 @@ var usd = (max) => z2.union([z2.string().regex(/^\d{1,12}(\.\d{1,8})?$/), z2.num
|
|
|
1114
1162
|
return n3;
|
|
1115
1163
|
});
|
|
1116
1164
|
var tokenRef = z2.union([ticker, evmAddr]);
|
|
1165
|
+
var chainRef = z2.union([z2.string().regex(/^[A-Za-z0-9._-]{1,30}$/), z2.number().int().positive()]);
|
|
1117
1166
|
var httpsUrl = z2.string().max(400).regex(/^https:\/\/\S+$/, "must be an https:// URL");
|
|
1118
1167
|
var slippageBps = z2.number().int().min(1).max(5e3).optional();
|
|
1119
1168
|
var HONEST = "REAL FUNDS, MAINNET: this executes IMMEDIATELY from the user's Agent Wallet, inside the caps set by the user/operator in the Zypher Agent app. There is NO confirmation step and this MCP never holds keys. Ask the human for explicit approval of the exact parameters BEFORE calling.";
|
|
@@ -1168,6 +1217,14 @@ var SPECS = [
|
|
|
1168
1217
|
shape: { direction: z2.enum(["deposit", "withdraw"]), amount },
|
|
1169
1218
|
description: `Move native HYPE between HyperEVM and ELYSIUM 99901 for the user's Agent Wallet (Boxa bridge): deposit = HyperEVM -> Elysium (needed before agent_elysium_swap / agent_elysium_launch), withdraw = Elysium -> HyperEVM (can take a while). ${HONEST}`
|
|
1170
1219
|
},
|
|
1220
|
+
{
|
|
1221
|
+
name: "agent_bridge",
|
|
1222
|
+
method: "POST",
|
|
1223
|
+
path: "/api/agent-api/bridge",
|
|
1224
|
+
swap: true,
|
|
1225
|
+
shape: { originChain: chainRef, destinationChain: chainRef, originToken: z2.string().min(1).max(60).optional(), destinationToken: z2.string().min(1).max(70).optional(), amount, recipient: evmAddr.optional() },
|
|
1226
|
+
description: `Bridge funds with Relay between chains (any supported chain to any, e.g. ethereum -> hyperevm, arbitrum -> base) from the user's Agent Wallet. originChain/destinationChain = a chain name or numeric id; tokens by symbol or 0x address (default: the native token). With an API token the recipient can only be the Agent Wallet itself (leave it out) or an EVM address on the owner's send allow-list; Solana recipients are not possible. For HYPE between HyperEVM and Elysium use agent_bridge_elysium instead. ${HONEST}`
|
|
1227
|
+
},
|
|
1171
1228
|
{
|
|
1172
1229
|
name: "agent_perp_order",
|
|
1173
1230
|
method: "POST",
|
|
@@ -1276,10 +1333,13 @@ function execTools(cfg) {
|
|
|
1276
1333
|
}));
|
|
1277
1334
|
}
|
|
1278
1335
|
|
|
1336
|
+
// src/index.ts
|
|
1337
|
+
import { z as z3 } from "zod";
|
|
1338
|
+
|
|
1279
1339
|
// package.json
|
|
1280
1340
|
var package_default = {
|
|
1281
1341
|
name: "@zypheragent/mcp",
|
|
1282
|
-
version: "0.
|
|
1342
|
+
version: "0.5.0",
|
|
1283
1343
|
description: "MCP server of Zypher Agent: Hyperliquid perp analytics, HyperSwap quotes on HyperEVM and Elysium market and launchpad feed for AI assistants. Read-only by default; optional execution (swaps, Elysium swap and token launch, bridge, perp orders, close, send) only through a user-created Agent Wallet API token. This package holds no keys.",
|
|
1284
1344
|
license: "MIT",
|
|
1285
1345
|
author: "Zypher Agent",
|
|
@@ -1341,7 +1401,13 @@ globalThis.fetch = (input, init = {}) => {
|
|
|
1341
1401
|
var execCfg = loadExecConfig();
|
|
1342
1402
|
if (!execCfg.enabled && execCfg.reason) console.error(`zypher-mcp: ${execCfg.reason}`);
|
|
1343
1403
|
if (execCfg.enabled && execCfg.warning) console.error(`zypher-mcp: ${execCfg.warning}`);
|
|
1344
|
-
var
|
|
1404
|
+
var uploadTool = {
|
|
1405
|
+
name: "upload_token_image",
|
|
1406
|
+
description: "Upload a token image (PNG, JPEG, GIF or WebP, up to 4 MB, given as base64 or a data: URL) and get back an https URL for the `image` field of agent_elysium_launch. Uploads to Boxa's image host through the Zypher API; no funds are involved and your API token is NOT sent. Rate limited (6 per minute).",
|
|
1407
|
+
shape: { imageBase64: z3.string().min(16).max(56e5) },
|
|
1408
|
+
handler: async (a) => uploadTokenImage(a.imageBase64)
|
|
1409
|
+
};
|
|
1410
|
+
var tools2 = execCfg.enabled ? [...tools, ...execTools(execCfg), uploadTool] : tools;
|
|
1345
1411
|
setExecEnabled(execCfg.enabled);
|
|
1346
1412
|
var server = new McpServer({ name: "zypher-agent", version: package_default.version });
|
|
1347
1413
|
for (const t of tools2) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zypheragent/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server of Zypher Agent: Hyperliquid perp analytics, HyperSwap quotes on HyperEVM and Elysium market and launchpad feed for AI assistants. Read-only by default; optional execution (swaps, Elysium swap and token launch, bridge, perp orders, close, send) only through a user-created Agent Wallet API token. This package holds no keys.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Zypher Agent",
|