Server data from the Official MCP Registry
Leveraged-yield router on Morpho. List strategies, simulate, and build UNSIGNED txs.
About
Leveraged-yield router on Morpho. List strategies, simulate, and build UNSIGNED txs.
Remote endpoints: streamable-http: https://api.spiralstake.xyz/mcp
Security Report
Remote MCP endpoint verified (114ms response). Server: spiralstake. 7 tools available. 2 trust signals: valid MCP protocol, registry import. 1 security issue detected.
7 tools verified · Open access · 2 issues found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Remote servers are capped at 8.0 because source code is not available for review. The score reflects endpoint verification only.
Permissions Required
This plugin requests these system permissions. Most are normal for its category.
How to Connect
Remote Plugin
No local installation needed. Your AI client connects to the remote endpoint directly.
Add this to your MCP configuration to connect:
{
"mcpServers": {
"xyz-spiralstake-leverage": {
"url": "https://api.spiralstake.xyz/mcp"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
Spiral Stake — mcp read-data backbone (Step 1a)
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) |
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 |
| 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.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Fetch
Freeby Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
mcp-creator-python
Freeby mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
MarkItDown
Freeby Microsoft · Content & Media
Convert files (PDF, Word, Excel, images, audio) to Markdown for LLM consumption
