MCP Endpoint

EchoLedger, inside your AI client.

A Model Context Protocol endpoint exposing eleven live tools over Uniswap V2/V3, Balancer weighted, and Curve stableswap pools — ten reactive analytics primitives plus BuildStateTwin, a portable State Twin you can run counterfactuals against locally. Connect from Claude, Cursor, or any MCP-compatible client, then ask in plain language or call the tools directly — the analytics are exact AMM math, powered by open-source defipy.

Endpoint · streamable-HTTP · authless
https://mcp.echoledger.ai/mcp
Install

Connect in one step.

Authless — no account, no API key. You supply an Ethereum RPC URL per call (bring-your-own-RPC); nothing is stored or logged.

Claude Code

claude mcp add --transport http echoledger https://mcp.echoledger.ai/mcp

Claude Desktop

Settings → Connectors → Add custom connector, using the endpoint URL above.

Cursor

Settings → MCP → Add new MCP server. Name echoledger, type http, URL the endpoint above.

Quickstart

A first call.

Once connected, ask a natural-language question and the agent picks the tool and fills the arguments — or call a tool directly with an arguments object like this:

Tool call — CheckPoolHealth on a mainnet V3 pool

{
  "name": "CheckPoolHealth",
  "arguments": {
    "pool_address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640",
    "rpc_url": "https://ethereum-rpc.publicnode.com",
    "pool_type": "uniswap_v3"
  }
}

Response (abridged)

{
  "version": "V3",
  "spot_price": 0.000414,
  "tvl_in_token0": 241360294.59,
  "tvl_in_token1": 143584.31,
  "num_lps": 1,
  "fee_pips": 500,
  "tick_current": -74265,
  "has_activity": false
}

The rpc_urlabove is a public node for trying it out — use your own provider (Alchemy, Infura, etc.) for production. It is read once, server-side, and never persisted.

API reference

Common parameters.

Every tool accepts these. Tool-specific parameters are listed under each tool below.

pool_addressstringrequired

On-chain address of the pool/pair (Uniswap pair, Balancer weighted pool, or Curve stableswap pool). Lowercase, uppercase, or checksum casing all accepted.

rpc_urlstringrequired

An Ethereum (or L2) JSON-RPC URL used to read live pool state. You supply it per call; it is never stored or logged.

pool_type"uniswap_v2" | "uniswap_v3" | "balancer" | "stableswap"required

Which protocol the pool belongs to. Each tool advertises only the values it accepts — the Uniswap tools take uniswap_v2/uniswap_v3, the Balancer tools balancer, the stableswap tools stableswap, and BuildStateTwin all four.

chain_idinteger

Optional guard. If supplied and the RPC reports a different chain, the call is rejected.

block_numberinteger

Optional. Pin the read to a historical block. Omit to read the latest block.

AnalyzePosition

V2 · V3

Decompose an LP position's PnL into impermanent loss, accumulated fees, and net result, measured against the entry basis you provide.

Analyze my position in this Uniswap V3 USDC/ETH pool.

Parameters
lp_init_amtnumberrequired

LP tokens held by the position, in human units.

entry_x_amtnumberrequired

Amount of token0 deposited at entry.

entry_y_amtnumberrequired

Amount of token1 deposited at entry.

lwr_tickintegerV3 only

Lower tick of the position range. Omit for full range / V2.

upr_tickintegerV3 only

Upper tick of the position range. Omit for full range / V2.

holding_period_daysnumber

Optional. If supplied, real_apr is annualized from net PnL.

Returns
net_pnlnumber

current_value − hold_value, in token0 numeraire.

il_percentagenumber

Pure price-divergence impermanent loss (fraction).

fee_incomenumber

Isolated fee component, in token0 numeraire.

real_aprnumber | null

Annualized net return (null unless holding_period_days given).

diagnosisstring

"net_positive" | "fee_compensated" | "il_dominant".

SimulatePriceMove

V2 · V3

Project a position's value at a hypothetical price change from the current pool state. Size-invariant paper value; fee income is not modeled.

If ETH drops 30%, what happens to my V3 position?

Parameters
price_change_pctnumberrequired

Fractional change from current price; must be > −1.0. e.g. −0.30 = a 30% drop. Or pass the vector form price_change_pcts.

price_change_pctsnumber[]

Vector form — sweep a grid of price changes in one call (≤256). Supply this OR the scalar, not both; returns an ordered array of results.

position_size_lpnumberrequired

LP tokens held, in human units; must be > 0.

lwr_tickintegerV3 only

Lower tick of the position range.

upr_tickintegerV3 only

Upper tick of the position range.

Returns
new_valuenumber

Position value at the simulated price (token0 numeraire).

il_at_new_pricenumber

Impermanent loss at the simulated price (fraction, ≤ 0).

value_change_pctnumber

Fractional change in position value from current.

new_price_rationumber

Alpha = new_price / current_price.

fee_projectionnull

Always null — fee projection is out of scope for this tool.

CheckPoolHealth

V2 · V3

Pool-level snapshot: TVL, reserves, spot price, LP concentration, fee tier, and activity. Answers “would I deposit into this pool?” at the pool level.

Is this V3 pool healthy?

Parameters
recent_windowintegerV2 only

Rolling window (swap count) for fee_accrual_rate_recent. Default 20; ignored on V3.

Returns
tvl_in_token0 / tvl_in_token1number

Total value locked in each token numeraire.

reserve0 / reserve1number

Decimal-adjusted reserves.

spot_pricenumber

Current price of token0 in token1 terms.

num_lps / top_lp_share_pctinteger / number

LP count and the top LP's share.

fee_pips / tick_currentinteger | nullV3 only

Fee tier (pips) and current tick; null on V2.

num_swaps / fee_accrual_rate_recentinteger | nullV2 only

Swap count and recent fee rate; null on V3.

DetectRugSignals

V2 · V3

Threshold-based rug-pull screen composed over pool health: suspiciously low TVL, top-LP concentration, and inactive-pool-with-liquidity.

Any rug signals on this V2 pair?

Parameters
lp_concentration_thresholdnumber

Top-LP share that trips the concentration flag. (0, 1]; default 0.90; pass 1.0 to disable.

tvl_floornumber

Minimum acceptable TVL in token0; values at/below fire the low-TVL flag. Default 10.0 — override per pair.

Returns
risk_levelstring

"low" | "medium" | "high" | "critical" (count-based bucket).

signals_detectedinteger

Count of fired signals (0–3).

tvl_suspiciously_lowboolean

TVL below the floor.

single_sided_concentrationboolean

One LP owns a dominant share.

inactive_with_liquiditybooleanV2 only

Liquidity present but no swap activity. Always false on V3.

detailsstring[]

Human-readable lines explaining which signals fired.

CalculateSlippage

V2 · V3

Slippage and price-impact decomposition for a proposed swap: spot vs execution price, slippage %, cost, and (V2) the max trade within 1% slippage.

How much slippage on a 50,000 USDC buy here?

Parameters
amount_innumberrequired

Amount of token_in to trade, in human units; must be > 0. Or pass the vector form amounts_in.

amounts_innumber[]

Vector form — quote a range of trade sizes in one call (≤256). Supply this OR the scalar, not both; returns an ordered array of results.

token_in_namestringrequired

Symbol of the input token (e.g. "USDC", "WETH") — must match one of the pool's two tokens.

lwr_tickintegerV3 only

Lower tick of the active range.

upr_tickintegerV3 only

Upper tick of the active range.

Returns
slippage_pctnumber

Slippage as a fraction of spot.

price_impact_pctnumber

Price impact of the trade.

spot_price / execution_pricenumber

Pre-trade spot and realized execution price.

slippage_costnumber

Cost in output-token units.

max_size_at_1pctnumber | nullV2 only

Largest trade staying within 1% slippage; null on V3.

AnalyzeBalancerLP

Balancer

Decompose a 2-asset Balancer weighted-pool position's PnL using the weighted-pool IL formula, where the base token's weight shapes IL magnitude. Fee income is not attributed in v1 (vault-level fees only).

How is my 80/20 BAL/WETH Balancer position doing?

Parameters
lp_init_amtnumberrequired

Pool shares held by this position, in human units.

entry_base_amtnumberrequired

Amount of the base (first) token deposited at entry.

entry_opp_amtnumberrequired

Amount of the opp (second) token deposited at entry.

holding_period_daysnumber

Optional. If supplied, real_apr is annualized from net PnL.

Returns
net_pnlnumber

current_value − hold_value, in opp-token numeraire.

il_percentagenumber

Weighted-pool impermanent loss (fraction).

base_weightnumber

The base token's pool weight (e.g. 0.8).

alphanumber

Current base-in-opp price ratio vs entry.

diagnosisstring

"net_positive" | "fee_compensated" | "il_dominant".

SimulateBalancerMove

Balancer

Project a 2-asset Balancer position's value at a hypothetical base-token price move from current state. IL depends on both the shock magnitude and the pool weights.

If BAL drops 30%, what happens to my BAL/WETH Balancer LP?

Parameters
price_change_pctnumberrequired

Fractional base-in-opp price change; must be > −1.0. Or pass the vector form price_change_pcts.

price_change_pctsnumber[]

Vector form — sweep a grid in one call (≤256). Supply this OR the scalar, not both; returns an ordered array.

lp_init_amtnumberrequired

Pool shares held, in human units; must be > 0.

Returns
new_valuenumber

Position value at the simulated price (opp numeraire).

il_at_new_pricenumber

Impermanent loss at the simulated price (fraction, ≤ 0).

value_change_pctnumber

Fractional change in position value from current.

new_price_rationumber

Alpha = new_price / current_price.

AnalyzeStableswapLP

Stableswap

Decompose a 2-asset Curve stableswap position's PnL via the amplified-invariant IL formula — small depegs can produce outsized IL at high A. Values in peg-numeraire.

Analyze my position in the crvUSD/USDC pool.

Parameters
lp_init_amtnumberrequired

LP tokens held, in human units.

entry_amountsnumber[]required

Per-token entry amounts in pool order — exactly 2 (2-asset pools only).

holding_period_daysnumber

Optional. If supplied, real_apr is annualized from net PnL.

Returns
il_percentagenumber | null

Amplified-invariant IL (null in the unreachable-alpha regime).

net_pnlnumber | null

current_value − hold_value, in peg-numeraire.

Ainteger

The pool's amplification coefficient.

token_namesstring[]

Pool tokens in order.

diagnosisstring

e.g. "at_peg" | "net_positive" | "il_dominant".

SimulateStableswapMove

Stableswap

Project a 2-asset stableswap position's value at a hypothetical peg shift. At high A, large shocks may be physically unreachable — those fields return null.

What happens to my USDC/DAI Curve LP if USDC depegs 2%?

Parameters
price_change_pctnumberrequired

Fractional shock to the current alpha; must be > −1.0. Or pass the vector form price_change_pcts.

price_change_pctsnumber[]

Vector form — sweep a grid in one call (≤256). Supply this OR the scalar, not both; returns an ordered array.

lp_init_amtnumberrequired

LP tokens held, in human units; must be > 0.

Returns
new_valuenumber | null

Value at the simulated peg (null if unreachable at this A).

il_at_new_pricenumber | null

IL at the simulated peg (null if unreachable).

value_change_pctnumber | null

Fractional value change (null if unreachable).

new_price_rationumber

Simulated alpha = 1 + price_change_pct.

AssessDepegRisk

Stableswap

Impermanent loss across a ladder of depeg levels for a 2-asset stableswap position, each with an optional constant-product (V2) benchmark.

How exposed is my crvUSD/USDC position to a depeg?

Parameters
lp_init_amtnumberrequired

LP tokens held, in human units; must be > 0.

depeg_token_namestring

Symbol of the asset assumed to depeg. Optional — defaults to the pool's first token.

depeg_levelsnumber[]

Depeg magnitudes in (0, 1). Default [0.02, 0.05, 0.10, 0.20, 0.50].

compare_v2boolean

If true (default), each scenario reports the equivalent V2 constant-product IL.

Returns
scenariosobject[]

Per level: depeg_pct, peg_price, il_pct, lp/hold value, v2_il_comparison.

depeg_tokenstring

The asset assumed to depeg.

current_peg_deviationnumber

Current deviation from peg.

n_assetsinteger

Number of pool assets (2).

BuildStateTwin

V2 · V3 · Balancer · Stableswap

Read a pool once and return a portable State Twin — the pool's state as JSON, with a content_hash. A client rehydrates it locally and runs unlimited counterfactuals off the MCP, zero further RPC. Spans all four pool types.

Build me a reusable twin of the USDC/ETH 0.05% pool.

Parameters
lwr_tickintegerV3 only

Optional position range, uniswap_v3 only. Omit for the full active-liquidity range; ignored for other pool types.

upr_tickintegerV3 only

Optional position range, uniswap_v3 only.

Returns
__type__string

Snapshot class — V2 / V3 / Balancer / StableswapPoolSnapshot.

(snapshot fields)various

pool_id, protocol, reserves, weights/A, fee/ticks, block_number, chain_id, …

content_hashstring

"0x" + sha256 over the body (sort_keys) — recompute to verify integrity.

The four scenario tools (SimulatePriceMove, SimulateBalancerMove, SimulateStableswapMove, CalculateSlippage) also take a vector input to sweep a grid in one call. BuildStateTwinreturns a portable twin you rehydrate locally to run those primitives off the MCP with zero further RPC — build once, run N. Full reference, including the twin round-trip: docs/TOOLS.md.

Usage notes

Things worth knowing.

Bring your own RPC

Any Ethereum or L2 JSON-RPC works (Alchemy, Infura, public nodes). Passed per call, read once server-side, never stored or logged — it is redacted from every receipt.

chain_id guard

Supply chain_idto have the call rejected if your RPC points at a different chain than the pool — catches a wrong-network RPC before it returns junk.

V3 ticks & liquidity

The twin is built from the pool’s full-range active liquidity. lwr_tick/upr_tick describe your positionrange and feed the concentrated-liquidity IL math — they don’t re-scope the pool snapshot.

Read-only

Analytics only — the endpoint never signs or sends transactions. Some fields are protocol-specific (marked V2 only / V3 only above) and return null on the other.

Errors

Structured, never silent.

Bad input or an unreachable RPC returns a clear error message (your RPC URL is scrubbed from it), not a crash or empty result.

BadPoolType

pool_type is not one of uniswap_v2 / uniswap_v3 / balancer / stableswap.

IncompatiblePoolType

The tool doesn't accept that pool_type (e.g. a stableswap tool on a uniswap_v2 pool) — rejected before any chain read.

MissingArgument

pool_address, rpc_url, or pool_type was omitted.

ChainMismatch

Declared chain_id ≠ the chain the RPC reports.

Error reading pool

RPC unreachable, or the address isn't a contract on that chain.

Token not found

token_in_name doesn't match either pool token (the error lists the available symbols).

How it works

The math is open. The reports are paid.

Each call reads live Uniswap V2/V3 pool state through your RPC, builds a stateless twin, runs a closed-form AMM primitive, and returns a typed result. Nothing is cached between calls.

The analytics are powered by the open-source defipy library and its State Twin substrate — the same methodology behind EchoLedger’s paid reports. The library is open and verifiable; this endpoint is the free, self-serve surface.