Atlas / MCP servers / hypurrquant / Perp

PerpBLOCK

mcp/hypurrquant/perp

Multi-DEX perpetual futures CLI + MCP server — Pacifica (Solana), Hyperliquid, Lighter (Ethereum). 18 MCP tools for AI-powered trading

Verdict
BLOCK
Grade
F
Trust score
41 /100
Exposed tools
37 34r · 3w · 0d
Transport
stdio
License
MIT
Stars
39
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://www.npmjs.com/package/perp-cli) [](https://www.npmjs.com/package/perp-cli) [](https://github.com/hypurrquant/perp-cli/blob/main/LICENSE)

Multi-DEX perpetual futures CLI — Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain).

npm install -g perp-cli       # global install
perp --json portfolio

# Or without global install (restricted environments)
npx -y perp-cli --json portfolio

Features

  • 4 Exchanges — trade, bridge, arbitrage across Pacifica, Hyperliquid, Lighter, Aster
  • Funding Rate Arb — perp-perp + spot-perp scan & one-command dual-leg execution
  • Portfolio — single call returns balances, positions, risk level across all exchanges
  • Funds — deposit, withdraw, transfer, multi-provider bridge (cctp/relay/debridge), inter-exchange rebalance — all in one group
  • Bots — TWAP, grid, DCA, trailing-stop with background job management
  • Agent-First Design — --json, --fields, --ndjson, --dry-run, runtime schema introspection
  • Safety — pre-trade validation, response sanitization, client-id deduplication

Setup

# Set exchange keys
perp wallet set pac      # Pacifica
perp wallet set hl          # Hyperliquid
perp wallet set lt          # Lighter (API key auto-generated)
perp wallet set aster       # Aster (BNB Chain)

# Or interactive setup wizard
perp setup

# Verify
perp wallet show

Same EVM key works for both Hyperliquid and Lighter.

Lighter API Key Index: Indexes 0–3 are reserved by Lighter's frontend (web/mobile). perp-cli defaults to index 4. Override with LIGHTER_API_KEY_INDEX env var, or use perp wallet agent approve lighter --api-key-index for managed agent slots. Valid range: 4–254.

Command Groups

Read from source at commit 7f12f6537268OBSERVED · 2026-10-08
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add perp-cli-skill --env ASTER_PRIVATE_KEY=${ASTER_PRIVATE_KEY} --env HL_PRIVATE_KEY=${HL_PRIVATE_KEY} --env HYPERLIQUID_PRIVATE_KEY=${HYPERLIQUID_PRIVATE_KEY} --env LIGHTER_API_KEY=${LIGHTER_API_KEY} -- npx -y @hypurrquant/[email protected]
claude-desktop
{
  "mcpServers": {
    "perp-cli-skill": {
      "command": "npx",
      "args": [
        "-y",
        "@hypurrquant/[email protected]"
      ],
      "env": {
        "ASTER_PRIVATE_KEY": "${ASTER_PRIVATE_KEY}",
        "HL_PRIVATE_KEY": "${HL_PRIVATE_KEY}",
        "HYPERLIQUID_PRIVATE_KEY": "${HYPERLIQUID_PRIVATE_KEY}",
        "LIGHTER_API_KEY": "${LIGHTER_API_KEY}"
      }
    }
  }
}
03

Exposed tools (37)

34 read · 3 write · 0 destructive.

ToolRiskDescription
--slwriteStop-loss price
--tpreadTake-profit price
Recurringreadclass:priceBinary|underlying:BTC|expiry:20260505-0600|targetPrice:79980|period:1d
arb-aggressivereadLow spread (10%), $100/leg, 5 positions — captures smaller opportunities
arb-conservativereadHigh spread threshold (30%), small size ($30/leg), 2 max positions
arb-standardreadMedium spread (20%), $50/leg, 3 positions, 3 exchanges
arb_scanreadScan for funding rate arbitrage opportunities across exchanges. Finds symbols with the largest funding rate spreads
dca-dailyreadBuy once per day, 30 orders — steady accumulation over 1 month
dca-dip-buyerreadBuy only when volatility is high — accumulate during dips
dca-hourlyreadBuy every hour, 24 orders — short-term aggressive accumulation
dca-sellerreadSell (short) periodically — dollar-cost average out of a position
explain_commandreadExplain what a perp CLI command does, its parameters, and any risks. Helps the user understand a command before running it
get_arb_comparereadCompare active arbitrage positions side by side — ROI, funding income, price PnL, and annualized returns for each position
get_balancereadGet account balance (equity, available margin, margin used, unrealized PnL) on an exchange
get_funding_analysisreadAnalyze funding income across exchanges — cumulative totals, annualized rates, and per-arb-position breakdown. Great for tracking funding arb profitability.
get_funding_ratesreadCompare funding rates across all 4 exchanges (Pacifica, Hyperliquid, Lighter, Aster). Returns rates per symbol with spread analysis
get_marketsreadGet all available perpetual futures markets on an exchange, including price, funding rate, volume, and max leverage. Works without API keys.
get_open_ordersreadGet all open/pending orders on an exchange
get_orderbookwriteGet the order book (bids and asks) for a symbol on an exchange. Works without API keys.
get_outcome_bookreadGet the orderbook for one outcome side. Public read — no API key needed.
get_outcome_marketsreadList active Hyperliquid Outcome markets (HIP-4). Each market has parsed metadata (underlying asset, target price, expiry, period) and per-side info (Yes/No name, encoding, asset id, current mid). Public read — no API key needed.
get_outcome_positionsreadGet the active account
get_outcome_viewreadGet a combined view of one outcome market: all sides
get_pnl_analysisreadP&L analysis combining trading fees and funding income — shows net profit/loss by exchange with daily breakdown
get_positionsreadGet all open positions on an exchange, including size, entry price, PnL, leverage
get_pricesreadGet cross-exchange prices for symbols. Fetches mark prices from all 4 exchanges for comparison
grid-aggressivereadTight range (±1.5%), 20 grids, 5x leverage — high frequency, high risk
grid-conservativereadWide range (±5%), 8 grids, small size, no leverage — low risk sideways strategy
grid-long-biasreadLong-biased grid (±3%), 10 grids — profit from uptrend + range trading
grid-standardreadMedium range (±3%), 12 grids, moderate size — balanced grid trading
health_checkreadPing all 4 exchanges and return connectivity status and latency
perpreadMulti-DEX Perpetual Futures CLI (Pacifica, Hyperliquid, Lighter, Aster)
portfolioreadCross-exchange portfolio summary: balances, positions, and risk metrics across all 4 exchanges
suggest_commandreadGiven a natural language trading goal, suggest the exact perp CLI commands to run. Does NOT execute anything — only returns commands for the user to review and run manually
trade_closereadClose an existing position. IMPORTANT: Call trade_preview first with the opposite side to show impact, then get user confirmation.
trade_executewriteExecute a trade. IMPORTANT: Always call trade_preview first and get explicit user confirmation before calling this tool. Supports market and limit orders.
trade_previewreadPreview a trade WITHOUT executing. Returns estimated fill price, fees, margin impact, and risk checks. ALWAYS call this before trade_execute and show the result to the user for confirmation.
04

Trust audit

BLOCKgrade F · trust 41/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)FAIL
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (2 observation(s))
Network
declared (9 observation(s))
Shell
declared (2 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/commands/portfolio.ts:899
if (process.platform === "darwin") exec(`open ${url}`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/commands/portfolio.ts:900
else if (process.platform === "linux") exec(`xdg-open ${url}`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHPrompt injection · prompt.credential_read · CWE-94, CWE-1427
<tool:get_outcome_book>:1
Get the orderbook for one outcome side. Public read — no API key needed.
Why it matters. asks the agent to read credentials
HIGHPrompt injection · prompt.credential_read · CWE-94, CWE-1427
<tool:get_outcome_markets>:1
List active Hyperliquid Outcome markets (HIP-4). Each market has parsed metadata (underlying asset, target price, expiry, period) and per-side info (Yes/No name, encoding, asset id, current mid). Publ
Why it matters. asks the agent to read credentials
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
src/commands/funds.ts:783
console.log(`  Token:   USDC  |  Min: $10  |  Gas: ${hasRelay ? chalk.green("FREE") : "SOL ~0.005"}`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
src/commands/funds.ts:787
console.log(`  Token:   USDC  |  Min: $5   |  Gas: ${hasRelay ? chalk.green("FREE") : "ETH ~0.0001"}`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
src/commands/funds.ts:791
console.log(`  Token:   USDC  |  Min: 1 (L1), 5 (CCTP)`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
src/commands/trade.ts:1404
console.log(`  ${b.token.padEnd(10)} ${b.total.padEnd(15)} available: ${b.available}`);
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/mcp-server.ts:1754
async ({ period, exchange: exFilter, symbol: symFilter }) => {
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/mcp-server.ts:1756
const exchanges = exFilter ? [exFilter] : ["pacifica", "hyperliquid", "lighter", "aster"];
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/mcp-server.ts:1833
async ({ period, exchange: exFilter }) => {
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/mcp-server.ts:1835
const exchanges = exFilter ? [exFilter] : ["pacifica", "hyperliquid", "lighter", "aster"];
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/__tests__/commands/agent-hl.test.ts:105
mockOws.createApiKey.mockReturnValue({ id: "key-hl-001", token: "ows_key_NEVER_STORED", name: "api-hl-perp-cli-hl" });
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/__tests__/commands/agent-lt.test.ts:150
mockOws.createApiKey.mockReturnValue({ id: "key-lt-001", token: "ows_key_NEVER_STORED" });
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/__tests__/commands/agent-wallet.test.ts:91
mockOws.createApiKey.mockReturnValue({ id: "key-001", token: "ows_key_NEVER_STORED", name: "api-aster-perp-cli-aster" });
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/__tests__/commands/agent-wallet.test.ts:526
mockOws.createApiKey.mockReturnValue({ id: "key-partial", token: "ows_key_NEVER_STORED", name: "api" });
LOWInformation disclosure · disclose.log_secret · CWE-209, CWE-532
src/__tests__/integration/spot-adapter-cross-validate.test.ts:414
console.log(`${token}: spot=$${spotMid.toFixed(4)} perp=$${perpPrice.toFixed(4)} deviation=${deviation.toFixed(0)}% (correctly rejected)`);
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/agent-wallet/errors-classify.test.ts:2
import { classifyError } from "../../errors.js";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/agent-wallet/expiry.test.ts:2
import { isExpired, daysUntilExpiry, formatExpiry } from "../../agent-wallet/expiry.js";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/agent-wallet/expiry.test.ts:3
import type { AgentMeta } from "../../settings.js";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/agent-wallet/lighter-keystore.test.ts:17
} = await import("../../agent-wallet/lighter-keystore.js");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/agent-wallet/passphrase.test.ts:18
const { resolvePassphrase } = await import("../../agent-wallet/passphrase.js");
LOWNetwork egress · net.env_exfil · CWE-200, CWE-319
src/__tests__/integration/spot-adapter-cross-validate.test.ts:14
".env" ... fetch(
Why it matters. reads secrets in the same file that sends data out
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/sdk, @msgpack/msgpack, @solana/web3.js, @types/react, bs58, chalk, cli-table3, commander
Why it matters. 26 dependency range(s) float
Fix. pin exact versions or ship a lockfile
INFOPrompt injection · prompt.credential_read · CWE-94, CWE-1427
skills/perp-cli/references/commands.md:312
### OWS (Open Wallet Standard) API key + policy — optional, scoped agent tokens
Why it matters. asks the agent to read credentials

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 7f12f6537268full audit observations/trust-audit/mcp-server/hypurrquant__perp.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-087f12f6537268BLOCKF41first audit
06

Questions

What is the Perp MCP server?

Multi-DEX perpetual futures CLI + MCP server — Pacifica (Solana), Hyperliquid, Lighter (Ethereum). 18 MCP tools for AI-powered trading

What tools does Perp expose?

37 in total: 34 read-only, 3 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is Perp safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (41/100) and found 4 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does Perp need?

It reads ASTER_PRIVATE_KEY, HL_PRIVATE_KEY, HYPERLIQUID_PRIVATE_KEY, LIGHTER_API_KEY, LIGHTER_API_KEY_INDEX, LIGHTER_PRIVATE_KEY, LT_PRIVATE_KEY, OWS_API_KEY, OWS_PASSPHRASE, PACIFICA_PRIVATE_KEY, PRIVATE_KEY and SECRET from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Perp run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @hypurrquant/perp-cli-skill at 0.5.3.

How current is this page?

The grade is for one exact copy of the source (7f12f6537268), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement