MetaLend
Server Details
Browse, deposit, withdraw & rebalance stablecoins on Aave, Morpho & Euler across major EVM chains.
The last two health checks of this connector failed. If this server requires authentication, missing or expired test credentials may be the cause. A test profile lets Glama authenticate for health checks and discover tools; it is separate from your personal connections.
If you are the author, claim ownership, then add or update a test profile under Admin → Test Profile.
- Status
- Unhealthy
- Uptime
- 89.7% over 60 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- rabeles11/metalend-mcp
- GitHub Stars
- 0
- Server Listing
- MetaLend
TDQS
Scored across 19 tools
The prepare/submit pairs, get_config vs get_default_config, and get_balances vs get_bridge_balances all have explicitly delineated boundaries spelled out in their descriptions, so an agent can navigate them. However, several small helper tools (get_withdrawal_version, get_token_info, get_transaction_costs) sit close in purpose, and the sheer number of read tools targeting wallet/chain/token state creates some borderline overlap.
Names follow a consistent snake_case verb_noun/verb_object pattern throughout: get_*, list_*, prepare_*, submit_*. The auth pair (get_auth_challenge/submit_auth_verify) and status pair (get_deposit_status/get_withdrawal_status) reinforce predictable conventions with no mixed casing or stylistic drift.
19 tools is slightly above the ideal band for a single-purpose server, but every tool maps to a real step in the protocol's multi-phase flows (SIWE auth, EIP-712 prep+submit for config/deposit/withdrawal, status polling, balances, pools, rewards). Nothing appears redundant or trivially filler, so the count is defensible even if heavy.
The surface covers the full auth → prepare → submit → poll lifecycle for deposits, withdrawals, and config, plus reads for balances, pools, config defaults, rewards, and token/gas metadata. Gaps exist (no rewards-claim submission, no way to pre-check in-progress rebalances or refills, no transaction history), but these are backend limitations the descriptions explicitly acknowledge rather than agent-facing blind spots.
Available Tools
19 toolsget_auth_challengeGet SIWE auth challengeAInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| chain | No | Chain name, e.g. BASE, ETHEREUM, POLYGON. Defaults to ETHEREUM if omitted. Cosmetic only — shown as the 'Chain ID:' line in the SIWE message text, does not need to match the chain passed to submit_auth_verify. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry generic readOnly/destructive/openWorld hints; the description supplies the real behavioral load: identical message returned for the same wallet within a short window, only one pending challenge per wallet, no auth side effect, and explicit rate limits (10/min, one per 6s). It even preempts the 'this looks like a caching bug' misread.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded, with the deprecation marker, the purpose, the signing requirement, and the caching caveat in descending order of importance. Every sentence carries information, though the caching/rate-limit passage is lengthy enough to be trimmed slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still names the returned `message` field and explains exactly what must be done with it. Combined with the dependency ordering and rate limits, an agent has everything needed to call this correctly and chain it into submit_auth_verify.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description goes beyond it by clarifying that `chain` does not affect which cached message is returned and does not need to match the value passed to submit_auth_verify. It adds genuine semantic value about a parameter's non-effect rather than restating the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (issue a SIWE challenge message for a wallet) and explicitly bounds it: 'Does NOT itself authenticate anything.' It also names the downstream sibling (submit_auth_verify), so an agent can distinguish it from the other auth/submit tools without opening a schema. The [DEPRECATED] prefix is front-loaded.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('required before any deposit/withdrawal/config-update tool') and names the follow-up call (submit_auth_verify with a personal_sign/EIP-191 signature). The main gap is that a deprecated tool does not point to its replacement, so an agent knows to avoid it but not what to use instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_balancesGet rebalancer balancesARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| tokens | No | Comma-separated token symbols to restrict to (e.g. 'USDC,USDT'). Omit for all supported tokens. | |
| walletAddress | Yes | The user's own wallet address (EOA or smart-contract wallet) — the owner address they used to make deposits. This is NOT the rebalancerAddress that this tool returns: never pass a rebalancerAddress here. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnly/openWorld/non-destructive); the description adds substantial depth beyond them: the returned rebalancerAddress must never be fed back as input, withdrawRequest EIP-712 data is included, gas fees from MetaLend-driven moves can make totals lower than deposits with no matching withdrawal, and a rate limit of 5 calls/min with a 12s minimum spacing. This is unusually rich disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and deprecation, then alternatives, then caveats. It is long, and the gas-fee/total explanation is dense, but each sentence carries operational information rather than filler, so the length is largely earned.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of explaining returns, and it does so concrete: field-by-field (rebalancerAddress, withdrawRequest data), plus explicit negatives (no rebalancingManagerAddress, no out-of-wallet pool catalog). Failure mode and rate limits are also covered, leaving no material gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are documented there, including the walletAddress-vs-rebalancerAddress warning, so the description adds little syntax or semantics beyond the schema. Baseline 3 is appropriate; it only weakly reinforces that 'tokens' implies per-token filtering.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource (get a wallet's deployed rebalancer balances) and enumerates the exact breakdown axes: per token, per chain, per protocol/pool, plus net earnings and blended APY. The deprecation marker is front-loaded, so an agent can distinguish and deprioritize it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to siblings under named conditions: get_config for rebalancingManagerAddress, list_pools for pool catalog/APY on pools the wallet isn't in, and get_default_config for wallets with no rebalancer yet. It also names a hard failure condition, which is exactly the when-not guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_bridge_balancesGet bridge balancesARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint, destructiveHint false, openWorldHint), and the description layers on genuinely non-derivable behavior: deprecation status, USDC-only support, concrete rate limits (20 calls/min, ≥3s spacing), and field-level semantics (sourcePool null vs populated, isForSpending meaning, absence of trackingId). This is well beyond what the annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the deprecated flag and purpose, followed by exclusion, applicability, field semantics, and rate limits — every sentence carries information an agent needs. It is dense to the point of being long, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by explaining the shape and meaning of returned entries (sourcePool, isForSpending, missing trackingId) that an agent could not otherwise know. Deprecation, token scope, rate limits, and routing to alternatives are all covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and schema description coverage is 100%, so the schema already documents walletAddress format and EIP-55 normalization. The description adds nothing parameter-specific, which is the correct baseline when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (get in-transit USDC bridge balances), scopes it ('funds moving cross-chain toward a destination pool'), and explicitly contrasts with the sibling get_balances for settled rebalancer balances. The deprecated tag and USDC-only constraint are stated up front, so an agent can select or avoid it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not ('Does NOT include already-settled rebalancer balances — use get_balances for those') and names the alternative for tracking a single deposit ('use get_deposit_status with the trackingId from that call instead'). Token applicability limit (USDC only) is also spelled out, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_configGet rebalancer configARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotation baseline (readOnlyHint/openWorldHint only): it discloses the misleading spendingCapRaw naming, that null/'0' means auto-funding is off rather than uncapped, that refills are weekly/bursty, the totalGasFee lifetime-drift behavior that could be mistaken for lost funds, the hasSignedConfig trap on template entries, and explicit rate limits (20/min, 1 per 3s). No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded, followed by field-level caveats. It is unusually long for a single-parameter read tool, and some clauses (the full spendingCapRaw mechanics) border on redundant with prepare_config, but nearly every sentence carries non-obvious semantic information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and does so: it explains the shape of configurations, the meaning of rebalancerExists, totalGasFee, spendingCapRaw/Formatted, and the returned addresses. An agent has enough to interpret results without additional documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and schema coverage is 100%, so the schema already documents the 0x-prefixed address and EIP-55 normalization. The description adds nothing about the parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a wallet's current rebalancer configuration per token') and enumerates the fields returned (protocols/pools/chains, frequency, lifetime deposits/withdrawals/fees, spending cap). It explicitly contrasts with get_balances ('Does NOT return live balances') and get_default_config, so an agent can route correctly. The DEPRECATED marker plus title make scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names alternatives for specific needs: get_balances for live balances, get_default_config when rebalancerExists is false. It also flags the tool as deprecated, which is important usage context. It stops short of stating the recommended replacement for the deprecated path, which is the one gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_default_configGet default rebalancer config for a tokenARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, destructiveHint=false, openWorldHint), but the description goes beyond them with rare, useful traits: rate limits of 20 calls/minute and no more than one call per 3s, plus the return payload shape. It does not state caching or error behavior, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Everything is packed into a single front-loaded paragraph: deprecation, purpose, payload, alternative, and rate limits, with no filler sentences. It is dense rather than ideally chunked, which keeps it just below a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read with no output schema, the description supplies the return contents, the sibling alternative, and the rate constraints. Nothing an agent needs to decide whether and how to call it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the token parameter is already documented with the same symbol examples the description repeats. The description adds no new syntax, validation, or format detail beyond the schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Get MetaLend's recommended default rebalancer configuration for a given token symbol') and even enumerates the payload (rebalancingManagerAddress, protocolIds, poolAddresses, domainIds). It explicitly distinguishes itself from the sibling get_config, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use condition ('Intended for wallets with no existing config yet') and names the alternative for the opposite case ('for an existing wallet's current config use get_config instead'). The [DEPRECATED] marker adds a further routing signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_deposit_statusGet deposit statusARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| trackingId | Yes | trackingId returned by submit_deposit. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safe-read profile (readOnly, non-destructive, openWorld), while the description adds rate limits (20/min, 1 per 3s), realistic timing windows (20-30 min, hours from Linea, 30+ min for EMERGENCY_WITHDRAW resolution), and the critical reassurance that EMERGENCY_WITHDRAW funds go back to the caller's own wallet rather than being lost. This is behavior an agent cannot infer from the schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The long state enumeration is justified because each status drives a different agent action, and deprecation plus the polling rule are front-loaded. The EMERGENCY_WITHDRAW explanation is somewhat repetitive ('not to the rebalancer, not lost or stuck'), costing a little tightness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return-value semantics — and it does, enumerating every status with its meaning and terminality. Combined with rate limits and timing expectations, an agent has everything needed to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Single parameter at 100% schema description coverage, so the schema already documents trackingId fully. The description's 'returned by submit_deposit' restates the schema text rather than adding new meaning, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Poll the status of a deposit by trackingId') and ties the input to its producer ('returned by submit_deposit'), which cleanly separates it from get_withdrawal_status and submit_deposit. The [DEPRECATED] marker is front-loaded so an agent immediately knows the tool's standing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives unusually explicit when-to-stop guidance: 'keep polling' for PROCESSING but 'treat this as done, do NOT keep polling' for BRIDGING, and notes SUCCESS/FAILED are terminal. It does not name a replacement tool despite the deprecation flag, which is the one missing routing signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rewardsGet rebalancer rewardsARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| reloadChain | No | Chain name to force a fresh reload for (e.g. 'BASE'). Omit to use cached data. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only declare readOnly/openWorld/non-destructive) by disclosing concrete rate limits (20/min, one call per 3s), the absence of RPC access to broadcast claims, and the exact semantics of a missing claimTransaction (nothing claimable, e.g. still vesting). It even flags the subtle trap that `to` is the RebalancingManager contract, not the item's own `distributorAddress`.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The deprecation warning and core purpose are front-loaded, and the dense claimTransaction guidance earns its space for a tool whose consumers must broadcast on-chain. There is mild redundancy, however — the server's inability to claim is stated more than once ('this server cannot claim rewards for you' / 'cannot do it for you').
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema available, the description carries the full burden and delivers, describing the return shape (rewards[].rewardItems[] with available balances and optional claimTransaction carrying to/abi/calldata) and the meaning of missing fields. Nothing an agent needs to interpret results or act on them is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (walletAddress, reloadChain) are fully described in the schema, so the description does not need to re-explain them. It adds no extra syntax or format detail for either parameter, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a wallet's aggregated rewards/earnings across all reward sources'), and explicitly delimits scope against the sibling get_balances ('Does NOT include base rebalancer yield/APY earnings — those are in get_balances' netEarning field'). It also flags the tool as DEPRECATED up front, so an agent can differentiate it without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context: it tells the agent what the tool covers, what it excludes (base yield lives in get_balances), and that no claim can be submitted server-side, so the agent knows this is read-only discovery. The main gap is that the [DEPRECATED] tag names no successor tool, leaving the agent to infer the replacement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_token_infoGet token infoARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| chain | Yes | Chain name, e.g. BASE, ETHEREUM, POLYGON. | |
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/no-destroy/open-world, so the bar is low, yet the description adds substantive context: deprecation status and hard rate limits (6 calls/minute, max one call per 10s). Those operational constraints are not derivable from any structured field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, and the deprecation marker is front-loaded so an agent sees it before committing. Every clause carries distinct information (purpose, return fields, motivating use case, rate limits).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description names the returned fields, which is sufficient for an agent to use the result. The one real gap is that a deprecated tool does not point to its replacement, leaving the agent without a migration path.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters carry their own descriptions with concrete symbol/chain examples, so the description need not restate them. It does not add syntax, casing, or alias rules beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a token's on-chain metadata') and enumerates the returned fields (display name, decimals, EIP-712 version) plus the chain scoping. This is clearly separable from siblings like get_config or get_balances without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete use condition: it is 'needed when building an EIP-3009 deposit signature's tokenName/tokenVersion fields.' It also flags deprecation, which is a negative-usage signal, but names no replacement tool or explicit alternative, so the routing guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_costsGet transaction costsARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds genuinely new behavioral facts: deprecation status and concrete rate limits (20 calls/minute, min 3s between calls). That rate-limit disclosure is valuable operational context not present in structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the deprecation tag so the agent sees the most decision-relevant fact first. No filler. Slightly dense with clauses, but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The per-chain output shape is gestured at ("broken down per supported chain") which is useful with no output schema present. But a deprecated tool with no successor named leaves an agent unsure what to do instead, and error behavior for an unsupported token is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is a single required 'token' parameter, so baseline is 3. The description adds nothing about token format or case sensitivity beyond the schema's own examples (USDC, USDT, etc.).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: returns on-behalf deposit/withdraw gas costs and minimum amounts per supported chain for a given token. It is clearly distinguishable from siblings like get_balances or get_config. It stops short of naming a sibling it competes with, but the resource is specific enough.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use before a deposit to check the amount meets the chain's minimum" gives a concrete trigger, which is better than nothing. However, the tool is flagged [DEPRECATED] and no replacement or migration path is named, which is exactly the guidance an agent needs most here. Usage is implied but the critical when-not path is missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_withdrawal_statusGet withdrawal statusARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| trackingId | Yes | trackingId returned by submit_withdrawal. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/safe profile, and the description adds substantial value beyond them: explicit rate limits (20 calls/minute, at most one call per 3s), a full terminal-vs-nonterminal state machine, and the absence of cross-chain bridging relative to deposits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight, front-loaded segments: deprecation flag, status semantics, then rate limits. Every sentence earns its place and the most important constraint is stated first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so by enumerating all status values with their meanings and terminality. An agent has everything needed to poll correctly and know when to stop.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single parameter, and the description's mention of trackingId only restates the schema's own note ('trackingId returned by submit_withdrawal'). Baseline 3 is appropriate; no additional syntax or format detail is added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Poll the status of a withdrawal by trackingId') and names the producing tool (submit_withdrawal). It also distinguishes itself from the deposit sibling by noting withdrawals have no cross-chain bridging leg, unlike deposits.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operational guidance: PROCESSING means keep polling, SUCCESS/FAILED are terminal, and it points to submit_withdrawal as the source of trackingId. However, the [DEPRECATED] marker names no replacement tool, leaving the agent without a migration path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_withdrawal_versionGet withdrawal contract versionARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, non-destructive, openWorld), and the description adds concrete rate limits (10 calls/minute, one call per 6s) and a deprecation warning. It does not say when the endpoint will be removed or what supersedes it, which is the one meaningful gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the deprecation warning, then semantics, then limits. Every clause carries actionable information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no parameters, the description carries the full burden and does so: it states what is returned (the version string), where it is used (EIP-712 domain for withdrawal signing), and the rate constraints.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the 0-param baseline applies. No misleading parameter claims are made.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (Get) plus precise resource ('contract signing version string required for the EIP-712 domain data used when signing a withdrawal'), which separates it from the withdrawal-status and prepare_withdrawal siblings. The [DEPRECATED] marker further qualifies its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Tells the agent the value 'rarely changes' and is 'safe to cache client-side', which is real operational guidance. It stops short of naming a replacement tool despite flagging deprecation, so the agent has no explicit migration target.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_poolsList rebalancer poolsARead-onlyInspect
[DEPRECATED] List all pools MetaLend's rebalancer can deposit into: protocol (Aave, Morpho, Euler, AaveV4), 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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/non-destructive annotations, it discloses deprecation status, a concrete rate limit (20/min, max one call per 3s), two data-quality caveats (ambiguous '0' TVL/liquidity, absence of paused/capacity flags), and where those states actually surface (submit_deposit/submit_withdrawal errors). This is unusually rich operational context that annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the [DEPRECATED] marker and the core purpose, then layered with exclusions, caveats, and limits — no sentence is filler. It is a dense paragraph rather than a structured list, which slightly hurts scannability for an agent parsing many caveats.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of describing return fields and does so explicitly, including the signData tuple needed downstream to build a config. Nothing an agent needs to call this correctly and interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is no parameter semantics to document. The description instead spends its space on return-field semantics (signData composition, APY decomposition), which is appropriate but not a parameter concern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource and enumerates exactly what each pool record contains (protocol, chain, APY breakdown, TVL, liquidity, signData). It explicitly separates itself from get_balances and get_config by stating what it does NOT return, so an agent can distinguish it from siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tools (get_balances / get_config) and the condition that selects them, and gives an actionable caller instruction ('filter out pools where blacklisted is true'). It also explains when an apparent zero value is not actionable information, which steers interpretation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_configPrepare a rebalancer config updateARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Token symbol this config applies to, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. | |
| domainIds | Yes | Chain domain IDs, one per poolAddresses entry, from list_pools' signData.domainId. Max 200 entries. For a smart-contract wallet, every distinct chain named here must independently verify the SAME signature — the standards supported for smart-wallet signature verification are ERC-1271 and ERC-6492 (counterfactual deployment). Supporting ERC-6492 is not the same as producing a cross-chain-transferable signature: some ERC-6492-compliant wallets intentionally bind their signature to a single network domain, so the same signature will never verify on a second chain regardless of 6492 support. Coinbase's Smart Wallet (Base Smart Wallet) is an example — it does support ERC-6492, but its signatures are domain-bound by design, so it does not support cross-chain signatures. For a wallet like that, keep domainIds single-chain — e.g. all Base, or all Ethereum, matching whichever chain the wallet's signature is scoped to — and sign the hashToSign with that wallet's signer on that exact chain; do not mix pools from other chains into the same config, that combination will always fail verification. | |
| protocolIds | Yes | 0=Aave, 1=Morpho, 2=Euler, 3=AaveV4 — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries. | |
| requiredTvl | No | Minimum pool TVL in USD required for a pool to be eligible as a rebalance target — pools below this are skipped when the rebalancer picks where to move funds. 0 (default if omitted) disables the filter. Max 500000000. Accepts a number or a numeric string, and is always returned/forwarded as a string to preserve exact decimal precision (the backend stores this as an unrestricted-precision decimal, and get_config's own response already serializes it as a string for the same reason — pass that value straight through, it is never converted through a JS number here, which would silently round a high-precision value). When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it to 0 (no floor). | |
| poolAddresses | Yes | Pool contract addresses to allow, from list_pools' signData.poolAddress. Max 200 entries. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. | |
| spendingCapRaw | No | Raw units, USDC only (must be "0"/null/omitted for every other token). "0" means this feature is off (the default if omitted or null — get_config's own response serializes it as null, pass that straight through). A nonzero value turns it on and is 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 — it funds a card (e.g. MetaMask card) tied to this wallet that spends directly from that Linea balance. It is not a spending/deposit/withdrawal ceiling and does not limit how much can be deposited or withdrawn elsewhere. MetaLend tops the wallet back up toward this target automatically (pulling from the rebalancer's own positions, bridging cross-chain if needed) on a weekly cycle and whenever the wallet makes a fresh USDC deposit — not instantly on every call. It also biases a USDC deposit whose source chain is Linea itself to land in the Linea Aave pool first (the cheapest source for that top-up) while the wallet's own Linea balance is still under this target. Must match exactly between prepare_config and submit_config. If set nonzero, must be at least 1000000 (1 USDC) and the config must include the Aave pool on Linea. | |
| includeRewardsApy | No | Whether reward-token (e.g. Merkle) APY counts toward the total-APY comparison used to pick the best pool to rebalance into — false restricts the comparison to native lending APY only. Defaults to true if omitted. When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it. | |
| collateralExposure | No | Whitelist of collateral asset symbols — applies only to Morpho vault selection; a vault is excluded from rebalancing if its own tracked collateral exposure includes any symbol not in this list. Each symbol must be one MetaLend actually tracks exposure for on at least one Morpho vault (see list_pools' collateralExposure values) — rejected here, before signing, otherwise. null (default if omitted) disables the filter entirely — an empty array is rejected, use null instead. Setting this to a non-null list also requires the config to include at least one Aave pool (rejected here, before signing, if none is present) whose live TVL (see list_pools' poolTvl) also meets requiredTvl — also rejected here, before signing, if none of the requested Aave pools currently qualify. When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently disable this filter. | |
| requiredLiquidityMultiplier | No | Requires a candidate pool's available liquidity to be at least this multiplier times the deposit amount (USD) before it's eligible as a rebalance target — a liquidity safety margin, not a percentage. 0 (default if omitted) disables the check. Max 1000. Accepts a number or a numeric string, and is always returned/forwarded as a string to preserve exact decimal precision (the backend stores this as an unrestricted-precision decimal, and get_config's own response already serializes it as a string for the same reason — pass that value straight through, it is never converted through a JS number here, which would silently round a high-precision value). When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it to 0 (no margin required). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations (readOnlyHint/openWorldHint/destructiveHint), which only say this call mutates nothing. The description discloses the exact hashing scheme (keccak256 of the abi-encoded tuple), that signing must be personal_sign over raw 32 bytes and not the hex string, the refusal invariants (nonzero-balance pool, invalid spendingCapRaw, unmapped pool tuples, all-blacklisted config), cross-chain verification semantics for ERC-1271/ERC-6492, and the rate limit (5/min, one per 12s). This is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded, but the body is a single ~600-word block of run-on, em-dash-chained sentences mixing refusals, cross-chain verification theory, a Coinbase Smart Wallet example, and rate limits. Much of the content is load-bearing, yet the density and lack of structure make it hard to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, no-output-schema, high-stakes signing tool, the description covers what is returned (hashToSign), what the caller must do with it, which failures are pre-validated here versus deferred to submit_config, and the 409 retryAfterSeconds behavior. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds cross-parameter semantics the schema does not consolidate: nonzero spendingCapRaw requiring an Aave-on-Linea pool, collateralExposure requiring an Aave pool whose live TVL meets requiredTvl, and the fact that pooling domainIds across chains always fails for domain-bound smart wallets. It also states the exact encoding order of the five tuple fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Build the signing hash for updating a wallet's rebalancer configuration... without signing anything.' It explicitly scopes the side-effect-free nature and names the downstream sibling (submit_config) that consumes the output, plus prepare_withdrawal and list_pools as related tools. An agent can distinguish this from submit_config without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives rich when-to-use/when-not guidance (build-then-sign-then-submit flow, EOA vs smart-contract wallet handling, retry-later on 409 rather than treating it as a signature problem). However, despite the explicit [DEPRECATED] tag, it never says what to use instead or whether the tool should still be called — a notable gap in routing guidance for a deprecated tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_depositPrepare a depositARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| chain | Yes | Chain name, e.g. BASE, ETHEREUM, POLYGON — the originating chain of this deposit: where the approve() call is broadcast, or for the signature flow, the chain the EIP-712 signature must validate on. Not where the rebalancer later invests the funds — deposits are naturally cross-chain in that sense, and this server only checks that the token has a signed config at all (hasSignedConfig), independent of which chains that config's domainIds allow. For an EOA, this originating chain is supported unconditionally: a raw ECDSA signature has no chain-specific verification step of its own, so any chain works. But when it comes to deposits done on a chain the wallet doesn't have configuration for, the deposit might fail if it's a smart-contract wallet that doesn't support cross-chain signatures (e.g. Coinbase's Smart Wallet / Base Smart Wallet) | |
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. | |
| amount | Yes | Raw token amount as a decimal-digit string (smallest denomination). Use get_token_info for decimals. | |
| method | No | Force a specific flow. Defaults to 'signature' for gasless-eligible tokens, else 'approval'. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnly/destructive/openWorld; the description adds substantial behavior: no signing, no RPC access to broadcast approvals, smart-contract wallets rejected even with valid ERC-6492 signatures, amount validated against chain minimum before returning, a fixed gas fee deducted from amount with expectedCreditedAmountRaw as the credited figure, and explicit rate limits (6/min, min 10s gap). 'Without signing anything' is consistent with readOnlyHint=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and next step, and nearly every sentence carries decision-relevant information (checks, signature limits, fees, rate limits). It is a single dense run-on paragraph with parenthetical asides and some duplication of schema field text (chain cross-chain caveats, token symbol lists), which costs it a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still tells the agent what the response contains (EIP-712 typed data or approve() params, `fee`, `expectedCreditedAmountRaw`) and the prerequisites, failure modes, and rate limits. An agent has everything needed to decide whether and how to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real semantics the schema does not: the default rule for `method` (signature for gasless-eligible, else approval), why smart-contract wallets may need method=approval, and the constraint that `chain` must be one that wallet can transact on. It does duplicate some schema content (token lists, chain caveats), keeping it below a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Build everything needed to deposit into MetaLend's rebalancer, without signing anything.' It immediately separates itself from the sibling submit_deposit by stating it produces unsigned payloads/signatures rather than executing, and flags the deprecation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes between the two flows (gasless tokens -> EIP-712 payload to sign; approval-only tokens -> broadcast approve() then call submit_deposit with no signature), names the next tool in each path, covers the smart-contract-wallet override via method: "approval", and states the prepare_config/submit_config prerequisite when get_config shows no signed config.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_withdrawalPrepare a withdrawalARead-onlyInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| chain | Yes | Chain name, e.g. BASE, ETHEREUM, POLYGON. | |
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. Required to disambiguate — some pool addresses serve multiple tokens. | |
| amount | No | Raw amount to withdraw. Omit or pass "MAX" for a full withdrawal (uses maxUint256). | |
| poolContract | Yes | Pool contract address, from get_balances' perPool[].poolAddress. Combined with `chain` to identify the exact balance — the same address can exist on several chains. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it is deprecated, it does not sign, it hard-refuses when live pool liquidity is insufficient, it deducts a fixed on-behalf gas fee so expectedReceivedAmountRaw differs from amount, and it is rate limited to 5 calls/minute with a 12s minimum interval. The readOnlyHint=true is consistent with a build-only payload tool and is reinforced, not merely restated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense single block but front-loaded with the DEPRECATED marker followed by purpose, and nearly every clause carries actionable information. It is slightly overlong and would scan better as separated sentences, but there is little wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing returns, and it does: the typedData payload, the fee, and expectedReceivedAmountRaw as the actual received amount. Combined with the error-prevention and rate-limit notes, an agent has everything needed to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds real semantics on top: the MAX/maxUint256 convention and why it is used (avoids stale-balance/rounding failures), and why chain is mandatory (same pool address reused across chains). It does not add further guidance for token or walletAddress beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Build the EIP-712 typed-data payload to sign for withdrawing from a specific pool, without signing anything.' It explicitly distinguishes itself from the sibling submit_withdrawal ('Pass the resulting signature to submit_withdrawal') and flags the deprecation up front.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the follow-on step (submit_withdrawal) and the conditions governing usage: omit amount or pass MAX for a full withdrawal, chain is required to disambiguate pools across chains, and the tool self-refuses when pool liquidity does not exceed the amount. An agent knows precisely when and how to call it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_auth_verifyVerify SIWE signature and get a JWTAInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| chain | No | Chain name, e.g. BASE, ETHEREUM, POLYGON. Defaults to ETHEREUM if omitted. For an EOA wallet this is irrelevant (signature recovery is chain-agnostic). For a smart-contract wallet, this MUST be the chain it has (or, if undeployed, would have via ERC-6492 counterfactual deployment) a valid signer on for this signature — it determines which chain's RPC is queried to validate it (ERC-1271/6492), and does not need to match the chain passed to get_auth_challenge. | |
| signature | Yes | personal_sign signature of the SIWE message from get_auth_challenge. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations (readOnlyHint=false, openWorldHint=true, destructiveHint=false): the server does not cache the JWT, the token is scoped to the signing walletAddress and mismatched use is rejected upstream, expiry is exposed via the response's expiresAt, and there are concrete rate limits (5/min, one per 12s). This is exactly the operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the deprecation flag, then purpose, then the auth-flow contract; no sentence is filler. It runs long for a single call, but the length is driven by genuinely necessary multi-step auth and rate-limit detail rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of return values and does so (jwt, expiresAt decoded from the JWT exp claim), plus scope, reuse, and throttling. An agent has everything needed to call it correctly and to handle the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so chain, signature, and walletAddress are already fully documented in the schema, including chain semantics for EOA vs smart-contract wallets. The description adds no parameter-level detail of its own, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb and resource: 'Exchange a signed SIWE challenge message (from get_auth_challenge) for a JWT scoped to that wallet.' It also names the upstream source tool and the downstream consumers (submit_deposit/submit_withdrawal/submit_config), so it is distinguishable from every sibling without opening a schema. The [DEPRECATED] prefix makes the tool's standing explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear sequencing (obtain challenge via get_auth_challenge, use returned jwt in the submit_* calls) and explicitly instructs reuse rather than re-authentication. It does not, however, say when *not* to call it or name a replacement for the deprecated path, which is the one thing an agent most needs once it sees [DEPRECATED].
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_configSubmit a rebalancer config updateADestructiveInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| jwt | Yes | JWT from submit_auth_verify for this walletAddress. | |
| token | Yes | Token symbol this config applies to, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. | |
| domainIds | Yes | Chain domain IDs, one per poolAddresses entry, from list_pools' signData.domainId. Max 200 entries. For a smart-contract wallet, every distinct chain named here must independently verify the SAME signature — the standards supported for smart-wallet signature verification are ERC-1271 and ERC-6492 (counterfactual deployment). Supporting ERC-6492 is not the same as producing a cross-chain-transferable signature: some ERC-6492-compliant wallets intentionally bind their signature to a single network domain, so the same signature will never verify on a second chain regardless of 6492 support. Coinbase's Smart Wallet (Base Smart Wallet) is an example — it does support ERC-6492, but its signatures are domain-bound by design, so it does not support cross-chain signatures. For a wallet like that, keep domainIds single-chain — e.g. all Base, or all Ethereum, matching whichever chain the wallet's signature is scoped to — and sign the hashToSign with that wallet's signer on that exact chain; do not mix pools from other chains into the same config, that combination will always fail verification. | |
| signature | Yes | Signature over prepare_config's hashToSign. | |
| protocolIds | Yes | 0=Aave, 1=Morpho, 2=Euler, 3=AaveV4 — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries. | |
| requiredTvl | No | Minimum pool TVL in USD required for a pool to be eligible as a rebalance target — pools below this are skipped when the rebalancer picks where to move funds. 0 (default if omitted) disables the filter. Max 500000000. Accepts a number or a numeric string, and is always returned/forwarded as a string to preserve exact decimal precision (the backend stores this as an unrestricted-precision decimal, and get_config's own response already serializes it as a string for the same reason — pass that value straight through, it is never converted through a JS number here, which would silently round a high-precision value). When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it to 0 (no floor). | |
| poolAddresses | Yes | Pool contract addresses to allow, from list_pools' signData.poolAddress. Max 200 entries. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. | |
| spendingCapRaw | No | Raw units, USDC only (must be "0"/null/omitted for every other token). "0" means this feature is off (the default if omitted or null — get_config's own response serializes it as null, pass that straight through). A nonzero value turns it on and is 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 — it funds a card (e.g. MetaMask card) tied to this wallet that spends directly from that Linea balance. It is not a spending/deposit/withdrawal ceiling and does not limit how much can be deposited or withdrawn elsewhere. MetaLend tops the wallet back up toward this target automatically (pulling from the rebalancer's own positions, bridging cross-chain if needed) on a weekly cycle and whenever the wallet makes a fresh USDC deposit — not instantly on every call. It also biases a USDC deposit whose source chain is Linea itself to land in the Linea Aave pool first (the cheapest source for that top-up) while the wallet's own Linea balance is still under this target. Must match exactly between prepare_config and submit_config. If set nonzero, must be at least 1000000 (1 USDC) and the config must include the Aave pool on Linea. | |
| includeRewardsApy | No | Whether reward-token (e.g. Merkle) APY counts toward the total-APY comparison used to pick the best pool to rebalance into — false restricts the comparison to native lending APY only. Defaults to true if omitted. When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it. | |
| collateralExposure | No | Whitelist of collateral asset symbols — applies only to Morpho vault selection; a vault is excluded from rebalancing if its own tracked collateral exposure includes any symbol not in this list. Each symbol must be one MetaLend actually tracks exposure for on at least one Morpho vault (see list_pools' collateralExposure values) — rejected here, before signing, otherwise. null (default if omitted) disables the filter entirely — an empty array is rejected, use null instead. Setting this to a non-null list also requires the config to include at least one Aave pool (rejected here, before signing, if none is present) whose live TVL (see list_pools' poolTvl) also meets requiredTvl — also rejected here, before signing, if none of the requested Aave pools currently qualify. When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently disable this filter. | |
| requiredLiquidityMultiplier | No | Requires a candidate pool's available liquidity to be at least this multiplier times the deposit amount (USD) before it's eligible as a rebalance target — a liquidity safety margin, not a percentage. 0 (default if omitted) disables the check. Max 1000. Accepts a number or a numeric string, and is always returned/forwarded as a string to preserve exact decimal precision (the backend stores this as an unrestricted-precision decimal, and get_config's own response already serializes it as a string for the same reason — pass that value straight through, it is never converted through a JS number here, which would silently round a high-precision value). When reconfiguring an existing signed config, copy this wallet's current value from get_config rather than omitting it, or you'll silently reset it to 0 (no margin required). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true, and the description goes well beyond them: specific 409 conflict conditions (in-progress rebalance/deposit, USDC funding-cap refill), a retryAfterSeconds hint, an explicit warning that a self-timeout may mean the update actually landed, and concrete rate limits (10/min, one per 6s). This is exactly the operational context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation and the deprecation flag, then a dense but waste-free second paragraph. The 409/rate-limit block is a long run-on, but every clause carries operational value and nothing is redundant with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter destructive mutation with no output schema, the description covers prerequisites, failure modes, retry behavior, and idempotency ambiguity. The remaining gaps are the missing deprecation replacement and no mention of what a successful response contains, both minor given the annotation set.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description still adds meaning the schema cannot: which argument carries the prepare_config hash, where the jwt must come from, and the explicit warning that this tool does not compute the signing hash or enforce the balance invariant itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Submit a signed rebalancer configuration update") and immediately distinguishes itself from the sibling pair it sits between: it consumes prepare_config's hashToSign and requires a jwt from submit_auth_verify. The [DEPRECATED] tag further separates it from any current-path tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite chain ("Always call prepare_config first") and names the source of both credentials (submit_auth_verify for jwt, prepare_config for the signed hash), plus retry guidance for 409s. It stops short of 5 because a deprecated tool never names its replacement, so an agent has no stated migration path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_depositSubmit a depositADestructiveInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| jwt | Yes | JWT from submit_auth_verify for this walletAddress. | |
| chain | Yes | Chain name, e.g. BASE, ETHEREUM, POLYGON — the originating chain of this deposit: where the approve() call is broadcast, or for the signature flow, the chain the EIP-712 signature must validate on. Not where the rebalancer later invests the funds — deposits are naturally cross-chain in that sense, and this server only checks that the token has a signed config at all (hasSignedConfig), independent of which chains that config's domainIds allow. For an EOA, this originating chain is supported unconditionally: a raw ECDSA signature has no chain-specific verification step of its own, so any chain works. But when it comes to deposits done on a chain the wallet doesn't have configuration for, the deposit might fail if it's a smart-contract wallet that doesn't support cross-chain signatures (e.g. Coinbase's Smart Wallet / Base Smart Wallet) | |
| nonce | No | From prepare_deposit's signature-method output. | |
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. | |
| amount | Yes | Raw token amount as a decimal-digit string (smallest denomination). Use get_token_info for decimals. | |
| signature | No | Signature over prepare_deposit's typedData. Omit for approval-based deposits. | |
| tokenName | No | From prepare_deposit's signature-method output. | |
| validAfter | No | From prepare_deposit's signature-method output. | |
| validBefore | No | From prepare_deposit's signature-method output. | |
| tokenVersion | No | From prepare_deposit's signature-method output. | |
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructive/openWorld/non-readOnly, but the description goes far beyond: jwt/auth requirements, 403 and 503 failure modes, the 10/min and 6s rate limits, timeout behavior, idempotency and double-spend safety, the 409 signature-already-used and 400 ApprovalValidationError semantics, and the exact signature format restriction. This is exactly the extra context the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is mostly relevant given the tool's complexity and is front-loaded with purpose and deprecation, but it is delivered as one dense run-on paragraph with nested parenthetical exceptions that is hard to scan. Several retry clauses overlap, so the structure costs more than the length alone.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and does so: it explains auth, method selection, error codes, idempotency, timeout recovery, and how to recover the trackingId for get_deposit_status. An agent has everything needed to call it correctly and recover from failure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real value: the all-six-or-none rule for validAfter/validBefore/nonce/signature/tokenName/tokenVersion, and the clarification that `amount` is used only for the pre-flight allowance check rather than the on-chain pull. These are semantics not present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first clause states a specific verb and resource ('Submit a deposit to MetaLend's rebalancer — moves funds') and marks the tool [DEPRECATED], which distinguishes it sharply from prepare_deposit and the read-only status siblings. The core action is clear, though it is somewhat buried under a paragraph dominated by retry/error semantics. It never names a replacement for the deprecated tool, which slightly weakens the differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states the prerequisite ('Always call prepare_deposit first'), the two alternative flows (signature vs approval-based, and when each applies), and concrete when-not rules (don't re-approve while an earlier submit is outstanding; use approval method for smart-contract wallets). This is unusually explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_withdrawalSubmit a withdrawalADestructiveInspect
[DEPRECATED] 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.
| Name | Required | Description | Default |
|---|---|---|---|
| jwt | Yes | JWT from submit_auth_verify for this walletAddress. | |
| chain | Yes | From prepare_withdrawal's output. | |
| token | Yes | Token symbol, e.g. USDC, USDT, MUSD, RLUSD, USDG, USDE, PYUSD. | |
| amount | Yes | From prepare_withdrawal's output. | |
| deadline | Yes | From prepare_withdrawal's output. | |
| signature | Yes | Signature over prepare_withdrawal's typedData. | |
| poolContract | Yes | ||
| walletAddress | Yes | EVM wallet address (0x-prefixed, 40 hex chars). Any casing is accepted — it is normalized to its EIP-55 checksum before being forwarded upstream. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true, and the description goes far beyond them: timeout semantics with trackingId recovery, 409 signature-already-used meaning a duplicate went through, 403 for wrong-wallet jwt, a Linea Aave USDC funding-cap 409 that list_pools/get_balances cannot surface, and rate limits of 20/min and one call per 3s. This is exactly the kind of non-obvious failure-mode context an agent cannot get from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite its length, it is front-loaded with the deprecated flag, the action, and the two preconditions before any edge-case detail, and nearly every sentence carries a distinct operational fact (timeout recovery, each error code, rate limit). There is no restatement of the name or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, no annotations covering the failure modes, and eight required parameters, the description carries the full burden and does: it explains prerequisites, on-chain signing scope, timeout/recovery, every documented error, and throttling. An agent can call and recover from this tool without external knowledge.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 88%, so baseline is 3, and the description genuinely adds value beyond it: the signature's EIP-712 domain is scoped to one chain with an ERC-6492 caveat for smart-contract wallets, and jwt/signature provenance is tied to specific upstream tools. It does not add much for token/amount/deadline beyond what the property descriptions already say.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Submit a withdrawal from MetaLend's rebalancer — moves funds" gives a specific verb and resource, and the [DEPRECATED] marker plus the prepare_withdrawal prerequisite clearly separate it from prepare_withdrawal and get_withdrawal_status among the siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Strong routing guidance: it names the required upstream calls (submit_auth_verify for jwt, prepare_withdrawal for typedData/chain/amount/deadline) and spells out the retry-vs-escalate decision tree on timeout. The one gap: it is flagged [DEPRECATED] but never names a replacement or a condition for choosing it over a successor, so an agent has no migration path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
- Changed
prepare_config1 field changed- changed
Input schema / properties / protocolIds / descriptionPrevious value: -"0=Aave, 1=Morpho, 2=Euler — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries."New value: +"0=Aave, 1=Morpho, 2=Euler, 3=AaveV4 — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries."
- Changed
submit_config1 field changed- changed
Input schema / properties / protocolIds / descriptionPrevious value: -"0=Aave, 1=Morpho, 2=Euler — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries."New value: +"0=Aave, 1=Morpho, 2=Euler, 3=AaveV4 — one entry per poolAddresses/domainIds entry, from list_pools' signData.protocolId. Pass only the exact set of (domainId, protocolId, poolAddress) pools you intend to allow, with no duplicate entries. Max 200 entries."
19 tool updates
- First observed
get_auth_challenge - First observed
get_balances - First observed
get_bridge_balances - First observed
get_config - First observed
get_default_config - First observed
get_deposit_status - First observed
get_rewards - First observed
get_token_info - First observed
get_transaction_costs - First observed
get_withdrawal_status - First observed
get_withdrawal_version - First observed
list_pools - First observed
prepare_config - First observed
prepare_deposit - First observed
prepare_withdrawal - First observed
submit_auth_verify - First observed
submit_config - First observed
submit_deposit - First observed
submit_withdrawal
Related MCP Connectors
Leveraged-yield router on Morpho. List strategies, simulate, and build UNSIGNED txs.
Analyse crypto wallets (EVM, Solana, Bitcoin) and compare DeFi lending, borrowing and pool rates.
Search 700+ DeFi vaults, compare risk scores, analyze protocols. No API key needed.
Crypto yield data for AI agents: lending, savings, staking, borrowing & stablecoin rates. 18 tools.
Related MCP Servers
- FlicenseAqualityDmaintenanceComplete DeFi intelligence — Yield, Staking, Restaking, RWA, Perps, Gas Optimization & Contract Security. One answer, not raw data.17-
- AlicenseAqualityAmaintenanceSelf-custodial crypto portfolio and DeFi MCP server. Read balances and positions (Aave, Compound, Morpho, Uniswap V3, Lido, EigenLayer) across Ethereum, Arbitrum, Polygon, and Base, and prepare transactions for approval on a Ledger via WalletConnect.10084 npm4Business Source 1.1
- AlicenseNot gradedqualityAmaintenancePhosphor is a local stablecoin portfolio manager that exposes an MCP server, enabling AI agents to read balances, composition, and costs, and propose actions like consolidation or policy changes, with all execution gated by explicit human approval in the app window.141 npm1BSD 3-Clause
- AlicenseAqualityCmaintenanceDeFi execution and agent-to-agent economy tools for AI agents — swaps, yield, transfers, policy enforcement, trust scoring, A2A jobs, and P\&L across Ethereum, Base, Arbitrum, and Polygon.311Apache 2.0
Glama MCP Gateway
Add one secure layer between your agents and this server.