Spiral Stake — mcp read-data backbone (Step 1a)
MCP serverDev toolsLeverage is a leveraged-yield router for Morpho. Once added, your AI can list available strategies, simulate them, and build transactions for you to sign. It only prepares unsigned transactions, so you review and approve each one before it is sent.
Use Spiral Stake — mcp read-data backbone (Step 1a) in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Spiral Stake — mcp read-data backbone (Step 1a) and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use Spiral Stake to list strategies
No key or account is asked for. Not verified by us yet: Ahel has not run a call through it.
Details
Available today. Use it from your connected AI after setup.
No key or account is asked for. Not verified by us yet: Ahel has not run a call through it.
Add Leverage, then ask your AI to list the available strategies and simulate one you are interested in. When you are ready, have it build the transaction so you can review and sign it.
What your AI can do with it
- List leveraged-yield strategies available on Morpho
- Simulate a strategy before committing anything
- Build unsigned transactions ready for your review and signature
- Route leveraged-yield activity through Morpho
Install Spiral Stake — mcp read-data backbone (Step 1a)
The server’s own address, for the clients that take one directly. Or connect Ahel once and every client you use reads it from one address, with the account kept on Ahel rather than in each client’s config.
Claude Code
claude mcp add --transport http --scope user spiral-stake-mcp-read-data-backb 'https://api.spiralstake.xyz/mcp'Run it once in your project, then open /mcp to approve any sign-in the server asks for.
Claude Desktop
https://api.spiralstake.xyz/mcpAdd a custom connector in Settings, paste this address, and approve the sign-in.
Cursor
cursor://anysphere.cursor-deeplink/mcp/install?name=spiral-stake-mcp-read-data-backb&config=eyJ1cmwiOiJodHRwczovL2FwaS5zcGlyYWxzdGFrZS54eXovbWNwIn0=Open the link and Cursor adds the server at that address.
ChatGPT
https://api.spiralstake.xyz/mcpIn Settings, enable Developer mode, create an MCP app, and paste this address. Your plan and workspace must allow custom apps.
Codex
codex mcp add spiral-stake-mcp-read-data-backb --url 'https://api.spiralstake.xyz/mcp'Run it once, then sign in with codex mcp login spiral-stake-mcp-read-data-backb if the server asks for an account.
From the project's README
As published by spiral-stake/mcp in README.md.
The composition authority + read API for Spiral Stake strategy data. It ports the app's client-side data composition server-side and serves it back as JSON, so three consumers run off one core:
- The app — the complete read surface it currently fetches, for a like-for-like Step-2 swap.
- Agents — the frozen
/strategiescontract. - Partners (later) — a clean, versioned, self-documenting REST surface (OpenAPI).
Read-only. No contract writes, no tx building, no signing, no private keys. It composes
numbers and serves JSON. The MCP tool layer, execution/build_*, and partner auth are later
steps — the seams are pre-cut (core + http) but not built.
Architecture
src/
core/ pure composition — no I/O, unit-testable
leverage.ts ← VERBATIM copy of v2-client/src/utils/leverage.ts (byte-diff gated)
apy.ts collateral-APY resolution (Pendle/DeFiLlama/Royco/StableWatch/on-chain)
leverageApy.ts 30/60/90d leveraged-APY windows + lumpy-token smoothing
compose.ts Market assembly from warm raw (port of FlashLeverage.createInstance)
strategy.ts Market → frozen /strategies contract (ladder, freshness, spiralHints)
exitLiquidity.ts exit-liquidity tier (the single verdict) + thresholds
sources/ one adapter per upstream (fetch + parse). native fetch + viem; no axios/wagmi
cache/ two-layer cache — RAW store (last-good) + warming policy (CONTRACT cadences)
warmer/ background scheduler (stale-while-revalidate); reads NEVER fetch
http/ thin hono REST layer (the only thing that knows about requests)
data/ static market config (copied from the app) + readMarkets port
config/ env (validated) + structured logger with correlation ids
Data flow: warmer fetches upstreams on the CONTRACT cadence → writes raw to the cache
(last-good on failure) → core composes strategies from warm raw only → http serves them.
A stale/failed upstream serves last-good with a visible stale age per field-group — never
dropped, never coerced to 0.
Run
cp .env.example .env # fill in RPC + API keys (secrets via env only)
npm install
npm run dev # tsx watch; serves on :$PORT (default 8787)
npm test # golden + parity gates
npm run typecheck # tsc --noEmit
npm run openapi # (re)emit openapi.json
node --import tsx scripts/smoke.ts # live: prime + print one composed strategy
/health (liveness + cache diagnostics) and /ready (503 until the warmer primes the required
data) are available immediately on boot.
Endpoints — app-read inventory → endpoint mapping
Every data read the app performs in v2-client/src/api-services/* maps to an endpoint here
(positions stay on the dashboard backend and are not reimplemented):
App read (api-services/*) | mcp endpoint |
|---|---|
getTokenApy, getAllMorphoMarketsData, fetchMerklSpotIncentives, prices, on-chain value → composed markets | GET /v1/strategies, GET /v1/strategies/:id |
FlashLeverage.createInstance → the app's full client-side Market[] composition | GET /v1/app/markets (raw domain model; BigNumber→{"$bn":…}, bigint→{"$bigint":…} — revive before use) |
morpho.ts getAllBorrowApyHistories / getBorrowApyHistory | GET /v1/markets/borrow-apy-history, GET /v1/markets/:id/borrow-apy-history |
apy.ts resolveTokenApyHistory (DeFiLlama/Royco/StableWatch history), chart.ts getApyChart | GET /v1/collateral/apy-history, GET /v1/collateral/:id/apy-history |
merkl.ts fetchMerklIncentiveData (borrow-incentive APR history) | GET /v1/markets/:id/incentive-history |
token.ts getAllLoanTokenPrices / getTokenPrice | GET /v1/prices |
chart.ts getMarketChart (CoinGecko price chart) | GET /v1/prices/chart?coinId=&days=¤cy= (on-demand proxy) |
chart.ts getDexOhlcv (DEX price chart for tokens with no CoinGecko/TradingView chart, e.g. CASHCAT/PONS on Robinhood) | GET /v1/prices/ohlcv?chainId=&token=&timeframe=&aggregate=&limit= (on-demand GeckoTerminal proxy, 30s cache, last-good on failure; COINGECKO_PRO_API_KEY lifts the rate limit) |
dashboard.ts getApySnapshot (StableWatch stable APY) | GET /v1/stable-apy — fetched directly from StableWatch as a warmed upstream; the mcp owns this data now and no longer depends on the dashboard /apy endpoint |
| — (protocol-level, not an app read) | GET /v1/tvl — protocol TVL across all supported chains, warmed every 5m from on-chain positions: tvlUsd = net user equity (collateral − debt, the DefiLlama TVL), grossTvlUsd = total looped collateral, borrowedUsd = total debt, plus positions/users; 503 until the first chain is computed |
| swap/meta-dex aggregators, referral, positions | out of scope (execution / backend domains) |
Cross-cutting: /v1 versioning, CORS limited to CORS_ORIGINS, a consistent error envelope
({ error: { code, message, correlationId } }), a correlation id per request (echoed as
x-correlation-id), structured JSON logs, and an OpenAPI 3.1 spec at /openapi.json (+ committed
openapi.json).
Parity gates
leverage.tsgolden-vector —test/golden/leverage.golden.test.tsfreezes fixed inputs → exact outputs;leverage.parity.test.tsasserts the file is a byte-for-byte copy of the app'sleverage.ts. This locks every APY/LTV/ladder number to the app./strategiescomposition —test/parity/strategies.compose.test.tsseeds the raw cache with a controlled fixture and asserts the composed contract field-by-field (sourcing, LTV math, ladder via the verbatimleverage.ts, freshness cadences,null-vs-absent,spiralHintsisolation). Runs offline in CI.- Live golden-set + app-surface parity —
scripts/capture-parity.tsprimes the warmer against real upstreams and writes the composed/strategies(+ apy/borrow histories) for a fixed market set totest/fixtures/. The parity diff vs the app is produced by feeding the same fixed inputs to the app's client-side composition and comparing (the app logs its composed markets); the PR commits the fixtures and the empty diff. This is the gate that lets us offload TVL safely.
Frozen decisions (parity-critical)
bignumber.jspinned to the app's9.3.1; no globalBigNumber.configchange →toFixed(2)/ rounding (ROUND_HALF_UP) identical.- On-chain reads via viem replace wagmi:
getCollateralValueInLoanToken(multicall3), stUSDSstr(), spUSDGvsr()(chain 4663). The app's (intentionally lossy)BigInt(liqLtv)from the JSON number is matched exactly, not "fixed". maxLeverage = calcLeverage(maxLtv);defaultLeverage = calcLeverage(safeLtv),safeLtv = maxLtv% − 0.75— exactly as the app derives them. Ladder = integer steps1x … ⌊maxLeverage⌋(LTV=(1 − 1/lev)·100) then the exactmax.- Exit slippage is baked into
collateralTokens.jsonby the app's weekly refresh script; its file mtime is theexitLiquidity.asOf. The tier (the only verdict) lives inspiralHintswith its thresholds; rawslippagePctstays underexitLiquidity,null(no route) preserved.
Tools it offers (10)
What this server listed when Ahel dialed its public endpoint in Oct 2026, with no key and no account of yours. The names are the server’s own.
list_strategiesget_strategyget_pricessimulate_leveragebuild_leverage_txget_positionsbuild_manage_txsimulate_equity_depositbuild_equity_deposit_txbuild_equity_exit_tx
Signals
- Last commit
- Oct 2026
Advanced
- Delivery
- leverage MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
- Item type
- mcp-server
- Key
xyz-spiralstake-leverage- Source
- github.com/spiral-stake/mcp
- Hosted endpoint
https://api.spiralstake.xyz/mcp