io.github.rabeles11/metalend
repo:https://github.com/rabeles11/metalend-mcp
Browse, deposit, withdraw & rebalance stablecoins on Aave, Morpho & Euler across major EVM chains.
- transport:
- remote
- credential class:
- open
Owner verification
Not yet verified. Verifying proves you control this server and is free, permanently — it never changes a published score.
Start verification →Tools
- get_auth_challengeshallow
Get a Sign-In-With-Ethereum challenge message for a wallet, required before any deposit/withdrawal/config-update tool. The returned `message` must be signed with personal_sign (EIP-191) by the wallet's own signer, then passed to submit_auth_verify. Does NOT itself authenticate anything — it only issues the message to sign. Repeated calls for the same walletAddress within a short window (a few minutes) return the SAME message rather than a fresh one — the backend only keeps one pending challenge per wallet at a time, and generating a new one would invalidate whatever an earlier caller is about to sign, so this is deliberate, not a caching bug. `chain` does not affect which cached message you get back. Rate limited to 10 calls/minute per caller, no more than one call every 6s.
- get_balancesshallow
Get a wallet's deployed rebalancer balances broken down per token, per chain, and per protocol/pool, including net earnings and blended APY. Also returns the wallet's rebalancerAddress (required only for approvals during deposits, never use this address as input into tools) and per-pool withdrawRequest EIP-712 data. Does NOT return rebalancingManagerAddress (needed for config signing) — use get_config for that. Does NOT return pool catalog/APY data for pools the wallet isn't in — use list_pools for that. Fails if the wallet has no rebalancer yet; use get_default_config to see what a first-time config would look like. Balances here already reflect every on-behalf gas fee paid so far — not just from this wallet's own deposits/withdrawals, but also from MetaLend automatically moving funds between pools/protocols/chains to chase yield or honor this wallet's config; each such move costs its own gas fee. So the total across pools can be slightly less than the sum of everything ever deposited, with no matching withdrawal — see get_config's `totalGasFee` for the lifetime total. Rate limited to 5 calls/minute per caller, no more than one call every 12s.
- get_bridge_balancesshallow
Get a wallet's in-transit USDC bridge balances (funds moving cross-chain toward a destination pool), including estimated completion time. Does NOT include already-settled rebalancer balances — use get_balances for those. Only applies to USDC. Other tokens do not support bridging. Each entry's `sourcePool` is null for a cross-chain deposit in transit, or a populated pool for an internal rebalance moving funds between pools; `isForSpending: true` marks a funding-cap refill specifically. There is NO trackingId on these entries — they cannot be correlated back to a specific submit_deposit call; use get_deposit_status with the trackingId from that call instead to track one particular deposit. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_configshallow
Get a wallet's current rebalancer configuration per token: which protocols/pools/chains are enabled, rebalance frequency, lifetime deposits/withdrawals/fees, and spending cap. `spendingCapRaw`/`spendingCapFormatted` (USDC only, null/"0" for every other token) is NOT a spending/deposit/withdrawal limit despite the name. When set (nonzero), it's the target balance MetaLend automatically keeps topped up in the wallet's OWN address (not the rebalancer contract) as Aave aUSDC + native USDC on Linea combined — funding a card tied to this wallet that spends directly from that Linea balance. Refills happen automatically on a weekly cycle and after fresh USDC deposits, not instantly. null/"0" means this auto-funding is off, not "uncapped" (there is no general spending ceiling to remove) — see prepare_config's own spendingCapRaw field description for the full mechanics. Also returns rebalancerAddress and rebalancingManagerAddress. Does NOT return live balances — use get_balances for that. `rebalancerExists: false` means the wallet has never configured a rebalancer; use get_default_config to see recommended starting values. Each configuration's `totalGasFee` is the lifetime sum of on-behalf gas fees this wallet has paid for this token — not just from deposits/withdrawals it explicitly requested. MetaLend periodically moves a wallet's funds between pools/protocols/chains on its own (chasing better yield, honoring `requiredTvl`/`requiredLiquidityMultiplier`/`collateralExposure`), and each such move is its own on-chain transaction with its own gas fee, deducted the same way a deposit/withdrawal fee is. So a wallet's balance can drift down slightly between get_balances polls with no deposit/withdrawal in between — that's this, not a bug or lost funds. IMPORTANT: `configurations` always includes a default/template entry for every supported token, whether or not the wallet ever signed one — a matching entry existing does NOT mean the wallet has a real config. Check that entry's `hasSignedConfig` to know if it's real. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_default_configshallow
Get MetaLend's recommended default rebalancer configuration for a given token symbol (e.g. 'USDC'): rebalancingManagerAddress plus recommended protocolIds/poolAddresses/domainIds. Intended for wallets with no existing config yet — for an existing wallet's current config use get_config instead. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_deposit_statusshallow
Poll the status of a deposit by trackingId (returned by submit_deposit). `status` is one of: PROCESSING — still confirming on-chain, keep polling; BRIDGING — deposit accepted, funds are now crossing chains via CCTP to the target pool (typically 20-30 minutes, up to several hours from Linea) — treat this as done, do NOT keep polling waiting for the bridge to finish; SUCCESS — terminal, deposit fully completed (reached directly for a same-chain deposit, or later for a bridged one once funds land — you do not need to wait for it after BRIDGING); FAILED — terminal, deposit did not go through; EMERGENCY_WITHDRAW — terminal but NOT success: after the bridge completed and funds reached the destination chain, the destination pool could not accept the deposit (e.g. it was at capacity), so funds were automatically sent back directly to your OWN wallet address — not to the rebalancer, not lost or stuck. This resolution (bridge completion plus destination-side processing) can itself take 30+ minutes after BRIDGING is first observed, so don't expect it right away. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_rewardsshallow
Get a wallet's aggregated rewards/earnings across all reward sources (e.g. Merkle), including claimed/available USD totals. Does NOT include base rebalancer yield/APY earnings — those are in get_balances' netEarning field. There is NO backend endpoint to submit a claim — this server cannot claim rewards for you. Each rewards[].rewardItems[] entry with an available balance carries an optional claimTransaction (chain-specific, per RewardItem.chain) with everything needed to broadcast the claim directly: `to` (send the transaction here — this is MetaLend's RebalancingManager contract, NOT the same item's own `distributorAddress`, which is only an input parameter, not the call target), `abi`, and pre-encoded `calldata`. Your own wallet must sign and broadcast this on-chain (this server has no RPC access and cannot do it for you) — if claimTransaction is absent on an item, treat it as nothing currently claimable there (e.g. still vesting) rather than assuming one should exist. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_token_infoshallow
Get a token's on-chain metadata (display name, decimals, EIP-712 version) for a given chain. Needed when building an EIP-3009 deposit signature's tokenName/tokenVersion fields. Rate limited to 6 calls/minute per caller, no more than one call every 10s.
- get_transaction_costsshallow
Get constant on-behalf deposit/withdraw gas costs and minimum deposit/withdraw amounts for a token, broken down per supported chain. Use before a deposit to check the amount meets the chain's minimum. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_withdrawal_statusshallow
Poll the status of a withdrawal by trackingId (returned by submit_withdrawal). `status` is one of: PROCESSING — still in progress, keep polling (withdrawals have no cross-chain bridging leg, unlike deposits); SUCCESS — terminal, withdrawal completed; FAILED — terminal, withdrawal did not go through. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- get_withdrawal_versionshallow
Get the contract signing version string required for the EIP-712 domain data used when signing a withdrawal. Rarely changes; safe to cache client-side. Rate limited to 10 calls/minute per caller, no more than one call every 6s.
- list_poolsshallow
List all pools MetaLend's rebalancer can deposit into: protocol (Aave, Morpho, Euler), chain, APY breakdown (native/rewards/total/net-of-fee), TVL, liquidity, and the signData (protocolId, poolAddress, domainId) needed to build a rebalancer config. Does NOT return a wallet's current balances or configuration — use get_balances / get_config for that. Callers should filter out pools where `blacklisted` is true. `poolTvl`/`poolLiquidity` can read "0" either because the pool is genuinely empty or because upstream data is momentarily missing — the two are not distinguishable here. There is no pool-level paused/capacity/deposit-or-withdraw-enabled flag: deposits can be paused globally, and withdrawals from specific pools can be temporarily blocked per-wallet (e.g. during a funding-cap refill) — neither shows up in this list, only as an error from submit_deposit/submit_withdrawal itself. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
- prepare_configshallow
Build the signing hash for updating a wallet's rebalancer configuration (which pools/protocols/chains it's allowed to move funds into), without signing anything. Computes keccak256(abi.encode(managerAddress, protocolIds, poolAddresses, domainIds, spendingCapRaw)) server-side — sign the returned hashToSign with personal_sign over its raw 32 bytes (not the UTF-8 text of the hex string) and pass the signature to submit_config. Refuses to build a config that would drop a pool you still hold a nonzero balance in — withdraw from it first (prepare_withdrawal) and retry. Also refuses an invalid `spendingCapRaw` (see its own field description for the exact rules), a non-null `collateralExposure` with no Aave pool included, containing an untracked symbol, or where no requested Aave pool's live TVL meets requiredTvl, any (domainId, protocolId, poolAddress) tuple that doesn't match a real pool in the current catalog for this token (see list_pools), or a config where every requested pool is blacklisted (see list_pools' `blacklisted` field) — a deposit under such a config would have no eligible destination and fail later, well after signing — rather than building a hash for it. For a smart-contract wallet: there is no single `chain` for this signature — the backend derives candidate chains straight from `domainIds` and requires the SAME signature to independently pass ERC-1271/ERC-6492 verification on EVERY chain named in domainIds, not just one; if the wallet doesn't have (deployed, or via ERC-6492 counterfactual deployment) a valid signer on all of them, the whole update is rejected. That signature must also be cross-chain transferable — supporting ERC-6492 counterfactual deployment does not by itself guarantee that. Some ERC-6492-compliant wallets intentionally bind their signature to a single network domain and are not cross-chain transferable — e.g. Coinbase's Smart Wallet (Base Smart Wallet) supports ERC-6492 but scopes its signature to one chain, so it does not support cross-chain signatures. For a wallet like that, keep `domainIds` restricted to that single chain (see domainIds' own field description) and sign on that exact chain, rather than mixing pools across chains. An EOA is unaffected (one ECDSA signature covers every chain). Even with a valid signature, submit_config can still be rejected with a 409 if a rebalance or deposit is currently in progress for this wallet+token, or (USDC only) a funding-cap refill is in progress — there is no read-only endpoint to check that ahead of time, so it is NOT pre-validated here; treat a 409 there as temporary and retry later (the error body includes a retryAfterSeconds hint), not as a problem with the signature itself. Rate limited to 5 calls/minute per caller, no more than one call every 12s.
- prepare_depositshallow
Build everything needed to deposit into MetaLend's rebalancer, without signing anything. For gasless tokens (USDC, MUSD, PYUSD) returns an EIP-712 ReceiveWithAuthorization typed-data payload — sign it with your own wallet and pass the signature to submit_deposit. For approval-only tokens (USDT, RLUSD, USDG, USDE) returns on-chain approve() parameters instead — your wallet must broadcast that approval itself (this server has no RPC access and cannot do it for you), then call submit_deposit with no signature. The signature flow only accepts a raw 65-byte EOA-style ECDSA signature — smart-contract wallets (including via ERC-6492 counterfactual deployment) are rejected regardless of validity, even for gasless-eligible tokens. A smart-contract wallet should instead pass `method: "approval"` explicitly here (works for any token, needs no signature at all) — but `chain` must then be one that wallet can actually transact on (see `chain`'s own field description); this server cannot validate that. Requires a signed rebalancer config for this token already (use prepare_config/submit_config first if get_config shows none) — and validates the amount against the chain's minimum deposit — before returning anything, so a doomed request never reaches signing. A fixed on-behalf gas fee (see `fee` in the response, also available standalone via get_transaction_costs) is deducted from `amount` before the rebalancer credits it — the response's `expectedCreditedAmountRaw` is what will actually show up in get_balances after the deposit lands, not the full `amount` you send. Rate limited to 6 calls/minute per caller, no more than one call every 10s.
- prepare_withdrawalshallow
Build the EIP-712 typed-data payload to sign for withdrawing from a specific pool, without signing anything. Looks up the exact withdrawRequest domain/types/value MetaLend expects from your current balances, fills in amount and a short-lived deadline, and returns it ready to sign with your own wallet. Pass the resulting signature to submit_withdrawal. Omit `amount` (or pass "MAX") to withdraw the pool's entire balance — this uses the maxUint256 convention rather than the exact current balance, which avoids stale-balance/rounding failures. `chain` is required: the same pool contract address can exist on multiple chains (e.g. Aave reuses one address across Polygon/Arbitrum/Avalanche/Optimism), so poolContract alone cannot disambiguate a wallet holding balance in that pool on more than one of those chains. Also refuses to build typedData when the pool's live liquidity (see list_pools' poolLiquidity) does not exceed the amount being withdrawn (this also applies to MAX, using the pool's own balance) — the backend would reject the signed request either way, so this catches it before a wallet signs. A fixed on-behalf gas fee (see `fee` in the response, also available standalone via get_transaction_costs) is deducted from the withdrawn amount before it reaches your wallet — the response's `expectedReceivedAmountRaw` is what will actually arrive, not the full `amount` being withdrawn from the pool. Rate limited to 5 calls/minute per caller, no more than one call every 12s.
- submit_auth_verifyshallow
Exchange a signed SIWE challenge message (from get_auth_challenge) for a JWT scoped to that wallet. The returned `jwt` must be passed explicitly as the `jwt` argument to submit_deposit/submit_withdrawal/submit_config for that same wallet — this server does not cache or store it. The JWT is only valid for the walletAddress that produced the signature; using it for a different wallet's write call will be rejected upstream. Reuse the same jwt for subsequent write calls to this wallet instead of re-authenticating every time — the response's `expiresAt` (decoded from the JWT's own exp claim) says how long it's good for. Rate limited to 5 calls/minute per caller, no more than one call every 12s.
- submit_configshallow
Submit a signed rebalancer configuration update. Requires a `jwt` from submit_auth_verify for this walletAddress and a `signature` over prepare_config's hashToSign. Always call prepare_config first — this tool does not compute the signing hash or check the balance invariant itself. Can return a 409 if a rebalance or deposit is currently in progress for this wallet+token, or (USDC only) a funding-cap refill is in progress — this is unrelated to the signature and not something prepare_config could have caught; wait and retry (the error body includes a retryAfterSeconds hint). This call can also time out on its own if the backend accepted the update but its response took too long to arrive — if that happens, check get_config afterward rather than assuming it didn't happen. Rate limited to 10 calls/minute per caller, no more than one call every 6s.
- submit_depositshallow
Submit a deposit to MetaLend's rebalancer — moves funds. Requires a `jwt` from submit_auth_verify for this walletAddress, and either a `signature` (from prepare_deposit's signature-method output) or, for approval-based tokens, no signature at all once your wallet has already broadcast the approve() transaction on-chain. Always call prepare_deposit first — this tool does not validate amounts or resolve addresses itself (it does reject a partial set of validAfter/validBefore/nonce/signature/tokenName/tokenVersion — provide all six, or none). This call can time out on its own if the backend accepted the deposit but its response took too long to arrive. For a signature-based deposit, the trackingId needed for get_deposit_status is still recoverable then: retry with the exact same signature/nonce — it cannot double-spend (a real duplicate is rejected with a 409 signature-already-used error, which itself confirms the original deposit went through), and that error's message now includes the original trackingId, so read it from there and call get_deposit_status directly rather than escalating to support. If that error's message doesn't include a trackingId (it's only included when the conflicting deposit belongs to this same wallet), treat the timeout as inconclusive rather than a failure and escalate to support with the wallet address and approximate time instead. For an approval-based deposit (no signature), retrying after an uncertain outcome is safe in the ordinary case without needing to check status first: this tool's own `amount` is only used by the backend to check against your current on-chain allowance before anything is broadcast — the on-chain deposit transaction itself takes no amount parameter, it just pulls and consumes your entire then-current allowance atomically. So if the original attempt already landed, a retry finds a zero allowance and is rejected outright with a 400 ApprovalValidationError from that same pre-flight check, before anything is broadcast on-chain, rather than moving funds again. The one exception: if you separately call token.approve() again for this token/spender while an earlier submit_deposit for it is still outstanding, a retry (or the original call, if it was merely delayed rather than failed) could then consume that new allowance as a second real deposit — avoid re-approving until you've confirmed via get_deposit_status that any earlier attempt for the same token has reached a terminal state. Can also fail with a 403 if the jwt wasn't issued for this walletAddress, or a 503 if deposits are temporarily paused platform-wide. The signature must be a raw 65-byte ECDSA signature (132 hex chars, 0x-prefixed) — anything else, including an ERC-6492-wrapped or other smart-contract-wallet signature, is rejected outright regardless of validity; there is no counterfactual/smart-wallet support for deposit signatures (unlike withdrawal/config signatures). Use the approval method instead for a smart-contract wallet. Rate limited to 10 calls/minute per caller, no more than one call every 6s.
- submit_withdrawalshallow
Submit a withdrawal from MetaLend's rebalancer — moves funds. Requires a `jwt` from submit_auth_verify for this walletAddress and a `signature` over prepare_withdrawal's typedData. Always call prepare_withdrawal first — this tool does not look up pool data or validate amounts. The signature's EIP-712 domain is scoped to this one `chain` — for a smart-contract wallet, it must have (or, if undeployed, would have via ERC-6492 counterfactual deployment) a valid signer on that exact chain (an EOA is chain-agnostic and unaffected). This call can time out on its own if the backend accepted the withdrawal but its response took too long to arrive — the trackingId needed for get_withdrawal_status is still recoverable then: retry with the exact same signature — it cannot double-spend (a real duplicate is rejected with a 409 signature-already-used error, which itself confirms the original withdrawal went through), and that error's message now includes the original trackingId, so read it from there and call get_withdrawal_status directly rather than escalating to support. If that error's message doesn't include a trackingId (it's only included when the conflicting withdrawal belongs to this same wallet), treat the timeout as inconclusive rather than a failure and escalate to support with the wallet address and approximate time instead. Can also fail with a 403 if the jwt wasn't issued for this walletAddress, or a 409 if withdrawing from the Linea Aave USDC pool specifically while a funding-cap refill for that wallet is in progress there (temporary; not visible ahead of time from list_pools or get_balances) — wait and retry. Rate limited to 20 calls/minute per caller, no more than one call every 3s.
Embed this server’s score
Tool count and median score across every tool in this server’s corpus — honest in a way a single cherry-picked tool’s badge wouldn’t be.
[](https://vouch.tools/servers/66146deb-0053-46d1-a1fc-8cb71f85a9a7)