Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
RPC_BATCHNoOpt into JSON-RPC batching: set to '1' to enable (off by default)
RPC_API_KEYNoAPI key for the RPC provider
RPC_PROVIDERNoRPC provider type: 'infura' or 'alchemy'
ONEINCH_API_KEYNo1inch API key for swap quote comparison
POLYGON_RPC_URLNoCustom RPC endpoint for Polygon
ARBITRUM_RPC_URLNoCustom RPC endpoint for Arbitrum
ETHEREUM_RPC_URLNoCustom RPC endpoint for Ethereum
ETHERSCAN_API_KEYNoEtherscan API key for contract verification lookups
RECON_FEEDBACK_ENDPOINTNoOptional HTTPS URL for request_capability to POST directly (requires proxy auth)
RECON_ALLOW_INSECURE_RPCNoOpt out of https/private-IP check on RPC URLs: set to '1' to allow (only for local forks)
WALLETCONNECT_PROJECT_IDNoWalletConnect Cloud project ID required for Ledger Live signing

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
get_lending_positionsA

Fetch all Aave V3 lending/borrowing positions for a wallet. Returns collateral, debt (both in USD and per-asset), health factor, LTV, and liquidation threshold across Ethereum and Arbitrum.

get_lp_positionsA

Fetch all Uniswap V3 liquidity-provider positions for a wallet. Returns token pair, current token amounts, fee tier, in-range status, uncollected fees (lower bound), and an approximate impermanent-loss estimate.

get_health_alertsA

READ-ONLY — across-protocol liquidation-risk check. Fans out in parallel to Aave V3 / Compound V3 / Morpho Blue (EVM, via wallet) and MarginFi / Kamino (Solana, via solanaWallet); returns every position whose health factor is below threshold (default 1.5). Each row carries protocol (discriminator), chain, market (market addr / marketId / MarginfiAccount / obligation; null for Aave's per-chain aggregation), healthFactor, collateralUsd, debtUsd, and marginToLiquidation (% HF would need to drop to hit 1.0). At least one of wallet / solanaWallet is required. Per-protocol failures (RPC down, MarginFi SDK IDL drift) are captured in the optional notes[] field rather than failing the whole call — a partial result still surfaces, and the absence of a protocol from the at-risk list is never silently wrong. Issue #427 (was Aave-V3-only despite generic name).

simulate_position_changeA

Simulate the effect of adding or removing collateral, or borrowing/repaying debt on a lending position. Returns the projected health factor and collateral/debt totals. Supports Aave V3 (default), Compound V3 (pass protocol: "compound-v3" + market Comet address), and Morpho Blue (pass protocol: "morpho-blue" + marketId bytes32). No transaction is sent.

get_safe_positionsA

Fetch Safe (Gnosis Safe) multisig accounts for an EVM owner address and/or by Safe address. Returns per-Safe threshold, owners, contract version, native balance, pending and recently-executed transactions, and risk notes (single-signer threshold, all-required threshold, Safe Modules, Safe Guards). Pass signerAddress to discover every Safe the wallet is an owner on, OR safeAddress to look up one Safe directly (or both — results are unioned and deduped). chains defaults to ["ethereum"]; pass an explicit array to query other supported EVM chains. Requires SAFE_API_KEY (https://developer.safe.global/) — Safe Transaction Service authenticates every request. ERC-20 balances are NOT enumerated here; pair with get_token_balance per token or get_portfolio_summary against the Safe address.

prepare_safe_tx_proposeA

Propose a new Safe (Gnosis Safe) multisig transaction. Wraps an inner action — either a previous prepare_*'s handle (recommended; pulls to/value/data from server-side state) OR raw to / value / data — into a SafeTx, computes its EIP-712 hash, and returns an UnsignedTx that calls Safe.approveHash(safeTxHash). The proposer broadcasts that approveHash via send_transaction; once mined, call submit_safe_tx_signature to post the proposal to Safe Transaction Service. Uses the on-chain approveHash flow (NOT off-chain eth_signTypedData_v4) — preserves the WalletConnect anti-Permit2-phishing scope. Default operation is CALL (0); DELEGATECALL (1) is high-risk and is flagged in the receipt.

prepare_safe_tx_approveA

Add an additional approveHash signature to a Safe (Gnosis Safe) transaction that's ALREADY in the queue (proposed elsewhere — Safe Web UI, another VaultPilot install, or a co-signer). Returns an UnsignedTx that calls Safe.approveHash(safeTxHash) for the given signer; broadcast via send_transaction, then call submit_safe_tx_signature to push the new signature to Safe Transaction Service. Use prepare_safe_tx_propose instead when you're proposing a NEW Safe tx.

submit_safe_tx_signatureA

After the on-chain approveHash tx has been mined (broadcast via send_transaction from the receipt of prepare_safe_tx_propose or prepare_safe_tx_approve), post the signature to Safe Transaction Service. Verifies on-chain that approvedHashes(signer, safeTxHash) != 0 first — refuses to post when the underlying approval doesn't exist yet. Auto-detects whether to call proposeTransaction (creates a new queue entry — when this server proposed the tx) or confirmTransaction (adds a signature to an existing entry — when another client proposed it). Returns the Safe Web UI deep-link so the user / co-signers can see the queue state.

prepare_safe_tx_executeA

Build the final on-chain execTransaction UnsignedTx that lands a Safe (Gnosis Safe) multisig payload. The executor doesn't need to have pre-approved on-chain — when msg.sender is an owner, the Safe contract treats their inline (r=msg.sender, s=0, v=1) signature as implicit consent. So one of the threshold "signatures" can be the executor themselves; the rest come from the on-chain approvedHashes registry filled by previous prepare_safe_tx_propose / prepare_safe_tx_approve calls. Refuses to build the tx when the threshold isn't met (which would just revert at execute time). Resolves the SafeTx body from the local store first, falling back to Safe Transaction Service. Returns an UnsignedTx the executor broadcasts via send_transaction — the OUTER tx sends 0 ETH (the inner value, if any, is paid by the Safe from its own balance during the inner CALL).

check_contract_securityA

Check Etherscan verification status, EIP-1967 proxy pattern, implementation/admin slots, and the presence of dangerous admin functions (mint, pause, upgradeTo, etc.) for a given contract. SCOPE: surfaces verification + admin-surface findings — protocol/contract safety only. It does NOT measure token upside, price direction, or investment merit. "No dangerous functions detected" means the admin surface is clean; it says NOTHING about whether the underlying token will appreciate. AGENT BEHAVIOR: this tool surfaces data; it does NOT pick. Do NOT use a clean security report as token-pick validation. Refuse speculative-pick prompts ("what coin will 100x", "should I buy X", "which token will moon") even when this tool was called; surface the security findings for due-diligence only. Issue #599.

check_permission_risksA

Enumerate privileged roles on a contract (Ownable.owner, AccessControl hints) and classify holders as EOA, Gnosis Safe multisig, or TimelockController. SCOPE: surfaces governance posture (who controls the contract, how hard would it be to rug). It does NOT measure token upside, price direction, or investment merit. A timelock-governed contract is harder to rug than an EOA-owned one — that's a safety floor, NOT an upside signal. AGENT BEHAVIOR: this tool surfaces data; it does NOT pick. Do NOT cite "governed by a multisig / timelock" as token-pick validation. Refuse speculative-pick prompts ("what coin will 100x", "should I buy X", "which token will moon") even when this tool was called; surface the permission findings for due-diligence only. Issue #599.

get_protocol_risk_scoreA

Return a 0-100 risk score for a DeFi protocol, combining TVL size, 30-day TVL trend, contract age, audit count (DefiLlama), and Immunefi bug-bounty status. Higher = safer. The protocol argument is the DefiLlama slug — works for any chain DefiLlama covers, not just EVM (Solana: marinade-finance, jito, kamino, marginfi, drift; Tron: justlend, sun-io; EVM: aave-v3, uniswap-v3, etc.). Issue #243. SCOPE: this score measures PROTOCOL-LEVEL contract safety, governance, and audit posture (will-the-protocol-rug risk). It does NOT measure individual token upside, price direction, future returns, or 'will this 100x' potential. A high score means the protocol is unlikely to be hacked or exit-scam; it says NOTHING about whether tokens custodied by, traded through, governed by, or related to the protocol will appreciate in price. AGENT BEHAVIOR: this tool surfaces data; it does NOT pick. Use it ONLY for protocol due-diligence ("is Aave V3 safer than Compound V3 to deposit into?"). Do NOT use it to ground speculative token-pick answers — "what coin will 100x", "best memecoin", "should I buy X", "which token will moon". Refuse speculative-pick prompts even when this tool was called; do not present a high score as upside, endorsement, or investment recommendation. Issue #599.

get_contract_abiA

READ-ONLY — fetch a verified contract's ABI on any Etherscan-V2-supported EVM chain (Ethereum, Arbitrum, Polygon, Base, Optimism). Wraps the same getsourcecode path prepare_custom_call and check_contract_security use, so the call carries the user's ETHERSCAN_API_KEY, the MAX_RESPONSE_BYTES cap, the sanitizeContractName discipline, and the 24h cache. Returns { chain, address, isVerified, isProxy, implementation?, contractName?, compilerVersion?, abi?, abiSource }. When the target is a proxy and followProxy=true (default), follows once to the implementation's ABI and reports abiSource: "proxy-implementation"; when followProxy=false or the implementation isn't verified, returns the proxy's own ABI with abiSource: "proxy-target" plus a proxyFollowSkippedReason explaining why. Unverified contracts return { isVerified: false } and no ABI — ask the user to paste the ABI inline if they have it from the project's published artifacts. ALWAYS prefer this tool over a generic WebFetch against etherscan.io/api.etherscan.io for ABI lookups in this MCP's surface — that path doesn't carry the API key (the env var lives in the MCP process, not the agent's harness), loses the size cap + verified-vs-unverified discipline, loses the 24h cache, and pulls the response through the agent's web layer with no sanitization for attacker-controlled fields like ContractName. Issue #495.

read_contractA

READ-ONLY — call any view/pure function on any verified-ABI EVM contract. Mirrors Etherscan's "Read Contract" tab and the symmetric counterpart of prepare_custom_call. Use for the long tail of on-chain reads no protocol-specific tool covers: OZ AccessControl role members (getRoleMember(bytes32,uint256), hasRole(bytes32,address)), governance proposal state, oracle prices, vault share prices, Safe owner enumeration, ERC-1155 balances, etc. ABI source: pass abi: [...] inline (preferred when you have the project's published artifact) OR omit it and the tool fetches via Etherscan V2 — refuses on unverified contracts with NO raw-bytecode fallback. Proxies are followed once to the implementation when Etherscan exposes the link. Pass fn as a name ("getRoleMember") when unambiguous, or as the full signature ("getRoleMember(bytes32,uint256)") to disambiguate overloads. args types are validated by viem's encoder — uint256 expects a decimal string, address expects 0x-prefixed hex, bytes32 expects 0x-prefixed 64-hex (e.g. an OZ role hash like keccak256("EXECUTOR_ROLE") = 0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63). Refuses on functions whose stateMutability is not view or pureeth_call would simulate a state-changing function and return a hypothetical result that has not occurred on-chain. Use prepare_custom_call for writes.

compare_yieldsA

READ-ONLY — return a ranked table of supply-side yield opportunities for a given asset across every integrated lending / staking protocol. v1 covers Aave V3 (5 EVM chains), Compound V3 (5 EVM chains, multi-market per chain), and Lido stETH (Ethereum only). Other protocols (Morpho Blue, MarginFi, Kamino, Marinade, Jito, EigenLayer, Solana native-stake) appear in the response's unavailable[] list with a coverage-gap reason — they need their wallet-less market readers split out from existing wallet-aware readers; tracked as follow-up work. Output per row: protocol, chain, market (free-form: 'cUSDCv3' for Compound, the asset symbol for Aave, 'stETH' for Lido), supplyApr (current, fractional 0.0481 = 4.81%), supplyApy (continuously-compounded), tvl (USD, may be null when the upstream doesn't expose it cheaply), riskScore (0-100 from get_protocol_risk_score, may be null), notes (pause flags, frozen reserves, etc.). Rows are sorted by supplyApr descending; null APR sinks. Filters: chains (default = all EVM mainnets + Solana); minTvlUsd (rows with tvl: null are NOT filtered — no data ≠ tiny market); riskCeiling (only show protocols at LEAST this safe; rows with riskScore: null are NOT filtered). Empty result returns emptyResultReason explaining whether nothing matched at all vs. everything filtered out. AGENT BEHAVIOR: this tool surfaces data; it does NOT pick. Surface the comparison verbatim. Do NOT pick a 'best' option for the user — they decide. The plan's positioning is explicit: 'Here are current supply rates' is right; 'I recommend depositing in X' is OUT.

get_staking_positionsA

Fetch Lido (stETH/wstETH) and EigenLayer staking positions for a wallet across supported chains. Returns per-protocol staked amounts, USD value, APR, and EigenLayer delegation target.

get_staking_rewardsA

Estimate staking rewards earned over a given period (7d/30d/90d/1y) using the current APR as a proxy. This is an estimate, not an on-chain rewards query.

estimate_staking_yieldA

Project annual yield on a hypothetical staking amount for Lido or EigenLayer using current APRs. Use this for 'what would I earn if I staked X ETH?' questions before the user commits capital. Returns the protocol, input amount, APR used, and projected annual rewards denominated in the same asset. Purely forward-looking — does NOT read any wallet or on-chain position; pair with get_staking_positions for actual holdings.

get_portfolio_summaryA

One-shot cross-chain portfolio aggregation for one or more wallets. Fans out across Ethereum/Arbitrum/Polygon/Base/Optimism (unless chains narrows it) and assembles: native ETH/MATIC balances, top ERC-20 holdings, Aave V3 and Compound V3 lending positions, Uniswap V3 LP positions, and Lido/EigenLayer staking — each valued in USD via DefiLlama. Pass tronAddress (base58, prefix T) alongside a single wallet to fold TRX + TRC-20 balances plus TRON staking into the same totals; breakdown.tron holds the TRON slice, tronUsd the subtotal, and tronStakingUsd the staking portion. Pass solanaAddress (base58, 43-44 chars) to fold SOL + SPL token balances into the totals; breakdown.solana holds the Solana slice and solanaUsd the subtotal (Solana staking lands in a follow-up phase). Returns a totalUsd, a breakdown by category and by chain, and the raw per-protocol position arrays. Default tool for 'what's in my portfolio?' / 'total value' questions; prefer it over calling each per-protocol reader separately.

get_portfolio_diffA

Decompose what changed in the user's portfolio over a time window — the AI version of an account statement. Returns the top-level USD change, broken down by chain and per-asset into: price moves (USD impact of price change on what was held the entire window), net deposits / withdrawals (sum of priced external transfers), and 'other' (the residual — interest accrual, swap legs, MEV, anything not cleanly attributable to price or external flow). Supports wallet (EVM), tronAddress, solanaAddress, bitcoinAddress — at least one required. Window: 24h / 7d / 30d / ytd. Returns BOTH a structured envelope AND a pre-rendered narrative string suitable for verbatim relay (control via format). Distinct from get_portfolio_summary (which gives current state) and get_pnl_summary (which gives the single net-PnL number) — this tool gives narrative decomposition. v1 caveats: history fetcher caps at ~50 items per chain, so very active wallets may under-count flows (response surfaces truncated: true); DeFi-position interest accrual collapses into the otherEffectUsd residual rather than its own bucket; Solana program-interaction txs (Jupiter swaps, MarginFi actions, etc.) are skipped from net-flow accounting (their balance deltas mix swap legs); Bitcoin shows current balance only (no in-window flow accounting yet).

share_strategyA

Generate a shareable, anonymized JSON snapshot of the user's portfolio STRUCTURE — protocol + asset + percentage of total — with NO addresses, NO absolute USD values, NO transaction hashes. Use this when the user wants to share their setup ("here's my Solana yield-farming strategy") with another VaultPilot user. Pass at least one of wallet / tronAddress / solanaAddress / bitcoinAddress / litecoinAddress, plus a name and optional description / authorLabel / riskProfile. The recipient pastes the returned jsonString into their own VaultPilot via import_strategy for read-only inspection. v1 emits JSON only; URL hosting is deferred to v2 (depends on hosted-MCP infra). Privacy guard: a regex scan runs on the output before emit and refuses (RedactionError) if any EVM 0x address, TRON T-address, Solana base58 pubkey, 64-hex tx hash, or Solana signature is detected anywhere in the JSON — including in user-supplied free-form fields. Percentages are rounded to 1 decimal to avoid wallet-fingerprint leakage. The strategy describes structure only; recipients cannot replicate amounts or addresses. Read-only — no signing, no broadcast.

import_strategyA

Parse and validate a shared-strategy JSON produced by share_strategy (someone else's, or one the user generated earlier). Pass either the stringified form or the parsed object via json. Returns the validated SharedStrategy for read-only inspection — protocol allocations, per-position percentages, optional health-factor / fee-tier / APR metadata. The same redaction scan that runs on emit also runs on import — addresses or tx hashes anywhere in the imported JSON cause a RedactionError, so a malicious sender cannot smuggle a wallet identifier through fields the recipient might not eyeball. Strict shape validation: unknown fields tolerated (forward-compat for v2 schema additions) but required fields must be present and well-typed. Read-only — no on-chain side effect, no signing.

generate_readonly_linkA

Generate a time-bound, revocable token that lets someone else read a specific subset of the user's wallets via their own VaultPilot instance. The classic use case: hand the token to a financial advisor or experienced friend so they can look at the user's DeFi positions without being given signing access. Pass wallets (at least one of evm / tron / solana / btc arrays — addresses validated against per-chain regex), optional name (auto-defaults to share-XXXX), expiresIn (1h / 24h / 7d / 30d, default 24h), and scope (read-portfolio only in v1). Returns the token ONCE — the issuer-side store keeps only sha256 of the token, so a recipient who paste-bombs the token into a public channel cannot have it re-emitted. Recipient runs import_readonly_token to decode and then queries the wallets via standard portfolio reads (get_portfolio_summary, get_lending_positions, etc.) using their own RPCs. Model A — the token is structured intent, NOT a security boundary: anyone holding it can query the listed addresses, but anyone could query those addresses without it (chain reads are public). Revocation (revoke_readonly_invite) is issuer-side bookkeeping; it doesn't recall a token already in the wild. Use list_readonly_invites to see what's outstanding. Read-only — no signing, no broadcast.

import_readonly_tokenA

Decode a vp1.… read-only share token (generated by someone else's generate_readonly_link) into the embedded wallet bundle. Accepts either the raw token or an http(s) URL containing a ?t=vp1.… / #t=vp1.… parameter. Returns { wallets, scope, name, issuedAt, expiresAt, id } — the recipient agent then passes those wallet addresses to standard portfolio reads (get_portfolio_summary, get_lending_positions, get_token_allowances, get_transaction_history, etc.) using the recipient's own configured RPCs. Refuses expired tokens with a clear error pointing the user back at the issuer. v1 stores nothing recipient-side — the agent juggles addresses in conversation; persistent recipient-side state is deferred. Read-only — no signing, no broadcast.

list_readonly_invitesA

List the read-only share tokens the user has generated. By default returns only ACTIVE invites (not revoked, not expired); pass includeInactive: true to see history. Each entry returns { id, name, scope, issuedAt, expiresAt, revokedAt, expired, active, walletCounts, totalAddresses } — note the addresses themselves are NOT re-surfaced here, only counts per chain (the raw token isn't stored either, only its sha256 hash). Pair with revoke_readonly_invite({ name }) to invalidate an invite. Read-only.

revoke_readonly_inviteA

Revoke a previously-generated read-only share invite by name. Marks the issuer-side record as revoked at the current time. Important caveat (Model A): this is issuer-side BOOKKEEPING — it does NOT recall the token already in the recipient's hands. Anyone holding the raw token can still query the listed addresses (chain reads are public regardless of whether the issuer wants the share to continue). Genuine recall requires Model B (hosted enforcement endpoint), deferred. Returns { revoked: { id, name, revokedAt } } on success; refuses if the name is unknown or already revoked.

get_daily_briefingA

One-paragraph 'what's going on with my portfolio right now' briefing — composed from existing tools, not new on-chain reads. Section coverage: (1) current portfolio total + window USD/% delta, (2) top 3 movers by absolute USD change across all chains, (3) Aave health-factor alerts (any HF < 1.5 surfaced with capitalized prefix and margin-to-liquidation %), (4) recent activity counts split into received / sent / swapped / supplied / borrowed / repaid / withdrew / other (action-type classification via 4byte-resolved methodName when present, directional fallback otherwise). Period: 24h (default — the morning-coffee briefing) / 7d / 30d. Address args mirror get_portfolio_diff (wallet / tronAddress / solanaAddress / bitcoinAddress — at least one required). Returns BOTH a structured envelope AND a pre-rendered markdown narrative (control via format). Sub-tool failures degrade to per-section notes rather than aborting (e.g. a Solana RPC outage doesn't void the EVM briefing). Two sections punted at v1 with explicit available: false reasons rather than silent omission: bestStablecoinYield (depends on the unshipped compare_yields tool) and liquidationCalendar (depends on the unshipped schedule_tx tool). Distinct from get_portfolio_summary (current state only) and get_portfolio_diff (window decomposition only) — this tool is the conversational AI rollup that sits on top of both.

get_pnl_summaryA

Wallet-level net PnL over a preset time window across EVM (Ethereum/Arbitrum/Polygon/Base/Optimism), TRON, and Solana. Returns the headline pnlUsd (= ending value − starting value − net user contribution), with per-chain and per-asset breakdown. Math: starting quantity per asset is reconstructed as currentQty − netFlowQty (clamped at zero when negative — user received the asset entirely within the window), priced at the period's start via DefiLlama historical, then pnlUsd = walletValueChange − (inflowsUsd − outflowsUsd). Use this for the simple 'how much did I make?' question; pair with get_portfolio_diff for the same window when the user wants the price-vs-quantity decomposition narrative. Periods: 24h / 7d / 30d / ytd / inception (capped at 365d in v1 — "since wallet creation" is not literal because the underlying history fetcher caps at ~50 items per chain). At least one of wallet / tronAddress / solanaAddress is required. v1 caveats: wallet token balances only (DeFi position interest accrual collapses into the residual); gas costs not subtracted; Solana program-interaction txs (Jupiter swaps, MarginFi actions, native staking actions) are skipped from net-flow accounting because their balance deltas mix intra-tx swap legs; truncation flagged when history caps. Bitcoin is intentionally NOT supported in v1 — the BTC path lacks in-window flow accounting and a price-effect-only number would be misleading.

explain_txA

Narrative analysis of a single confirmed transaction. AGENT BEHAVIOR: when the user pastes a tx hash (or an Etherscan / Arbiscan / Polygonscan / Basescan / Optimistic-Etherscan / Tronscan / Solscan URL containing one) and asks 'why did this fail / what does this do / what happened', call THIS tool — do NOT WebFetch the explorer or a Tenderly/Phalcon dashboard URL. Those pages are JS SPAs that render an empty shell when fetched server-side; this tool decodes the same data structurally and returns a verbatim-relayable narrative. Walks what actually happened: top-level method/instruction call, decoded ERC-20/TRC-20 Transfer + Approval events (or Solana SPL balance deltas), per-token balance changes for the wallet, fee paid, and a heuristics block flagging surprises (failed status, unlimited approval, dust outflow, transfer-to-zero burn, high-gas vs. moved value, unexpected no-state-change). Returns BOTH a structured envelope and a pre-rendered narrative string for verbatim relay (control via format). Distinct from get_transaction_status (just confirmation status) and the prepare→preview→send pipeline (forward-looking). Useful for debugging ("why did this swap return less than the quote?"), learning ("what does this contract call actually do?"), forensics ("what addresses did this tx touch?"), and address-poisoning triage. v1 covers EVM (Ethereum/Arbitrum/Polygon/Base/Optimism), TRON, and Solana — Bitcoin is deferred. v1 reads top-level execution only; internal calls / CPI / DeFi compositions surface via balance & event effects rather than as separate step rows. Pricing is current spot via DefiLlama (not historical at tx time). Optional wallet arg recomputes balance/approval changes from THAT wallet's perspective — defaults to tx sender. Read-only — no signing, no broadcast.

get_transaction_historyA

Fetch a wallet's recent on-chain transaction history on a single chain, merged across external (user-initiated) txs, ERC-20/TRC-20 token transfers, and internal (contract-initiated) txs. Results are sorted newest-first, capped at limit (default 25, max 50), and annotated with decoded method names (via 4byte.directory) and historical USD values at the time of each tx (via DefiLlama). Supports Ethereum/Arbitrum/Polygon/Base/Optimism via Etherscan, TRON via TronGrid, and Solana via the configured Solana RPC. On Solana, results include a fourth item type program_interaction for DeFi calls (Jupiter swaps, Marinade/Jito liquid staking, Raydium/Orca swaps, native validator staking, or any unknown program) with balance-delta summaries showing net SOL + SPL changes for the wallet across the tx — more useful than raw instruction data for 'what happened to my wallet?'. includeInternal has no meaning for TRON (silently ignored) or Solana (doesn't have an 'internal' concept — CPI effects are captured inside program_interaction deltas). Use this to answer 'what did I do last week?', 'show me my recent swaps', or 'did I already approve X?' without the user pasting tx hashes. Read-only — no signing, no broadcast. Items may carry an optional suspectedPoisoning field flagging address-poisoning heuristics: zero_amount_transfer (USDC transferFrom 0-amount exploit, chain-agnostic), vanity_suffix_lookalike (dust tx whose counterparty mimics another counterparty's first-4 + last-4 hex chars; mimics field names the matched address), and self_suffix_lookalike (counterparty mimics the wallet itself). EVM-only for the suffix rules. AGENT BEHAVIOR: this field is for you, NOT for the user. Do NOT include flagged entries in the user-facing summary — they're noise that crowds out real activity (a single poisoned wallet can have dozens of dust-lookalike entries pinned at the top by recency). Filter them out silently; if the user asks 'is that everything?' or you want to be transparent about the filter, mention briefly like 'hid N suspected-poisoning entries (use the raw response if you want to inspect them)'. Surface a flagged entry only when the user explicitly asks about a specific tx hash that happens to match, or about address-poisoning attempts on this wallet. The point of the flag is to keep poisoning data accessible to your reasoning (e.g. when validating a future prepare_* recipient against the wallet's history) WITHOUT polluting chat with scam noise.

get_swap_quoteA

Get a LiFi aggregator quote for a token swap (same-chain) or bridge (cross-chain). Returns expected output, fees, execution time, and the underlying tool selected. Default is exact-in (amount = fromToken); set amountSide: "to" for exact-out quotes (amount = target toToken output). Source chain is always EVM. Destination can be any EVM chain, Solana, or TRON — pass toChain: "solana" / toChain: "tron" + an explicit toAddress (Solana base58 / TRON T-prefixed base58); the bridge protocol delivers tokens on the destination chain after the EVM source tx confirms (typically 1-15 min). Exact-out is not supported for cross-chain bridges to Solana or TRON. For Solana-source swaps and bridges (the reverse direction) use prepare_solana_lifi_swap. TRON-source LiFi is not yet wired. PROTOCOL ROUTING (issue #411): without exchanges / bridges, LiFi picks the best-output route across all aggregators (Sushi, Uniswap, 1inch, Paraswap, etc.). When the user names a specific DEX ("swap on 1inch"), pass exchanges: ["1inch"] so LiFi only routes via that DEX — without the filter, the prepare receipt would silently use a different protocol. The response's routedVia.tool is the actually-resolved route; surface it to the user before they sign. No transaction is built by this tool.

prepare_swapA

Prepare an unsigned swap or bridge transaction via LiFi aggregator. Same-chain swaps use the best DEX route; cross-chain swaps use a bridge + DEX combo. Default is exact-in (amount = fromToken); set amountSide: "to" for exact-out (amount = target toToken output, e.g. "I want 100 USDC out"). Source chain is always EVM. Destination can be any EVM chain, Solana, or TRON. For non-EVM destinations pass toChain: "solana" / "tron" + an explicit toAddress in the destination chain's format; the user signs an EVM tx and the bridge protocol delivers tokens to the destination after confirmation. The destination-side decimals cross-check is dropped for non-EVM destinations (we can't read SPL/TRC-20 via EVM RPC); LiFi's reported decimals are the source of truth there. Exact-out is not supported for cross-chain-to-non-EVM. For Solana-source swaps and bridges use prepare_solana_lifi_swap. TRON-source LiFi is not yet wired. PROTOCOL ROUTING (issue #411): without exchanges / bridges, LiFi picks the best-output route across all aggregators. When the user explicitly names a DEX ("swap on 1inch", "use Sushi"), pass exchanges: ["1inch"] (or the named protocol) — without the filter LiFi may silently route via a different DEX. If no route satisfies the filter the call errors with a clear message; the agent can offer to retry without the filter. The unsigned tx's description includes "via " and notes whether the resolved tool matched the filter. DECODING DEFENSE: every cross-chain bridge calldata is parsed into its BridgeData tuple and the encoded destinationChainId + receiver are cross-checked against what the user requested — refuses on mismatch. Catches a compromised MCP that returns calldata routing to a different chain or recipient than the prepare receipt advertises. INTERMEDIATE-CHAIN BRIDGES: NEAR Intents (notably for ETH→TRON USDT routes) settles on NEAR and releases on the final chain via an off-chain relayer, so its on-chain destinationChainId is NEAR's pseudo-id (1885080386571452) rather than the user's requested chain. The defense allows this ONLY for an explicit hardcoded (bridge name, intermediate chain ID) pair held as a source-code constant — not loaded from env / config / LiFi response — so a compromised aggregator can't claim arbitrary chains as 'intermediate'. Receiver-side checks (non-EVM sentinel, etc.) still apply unchanged. The returned tx can be sent via send_transaction.

prepare_uniswap_swapA

Prepare a direct Uniswap V3 swap (bypasses LiFi aggregator). Use this ONLY when the user explicitly asks for Uniswap — otherwise default to prepare_swap which compares routes across venues. Same-chain only (Uniswap V3 is not a bridge). Auto-picks the best pool fee tier (100/500/3000/10000 bps) by quoting all four against QuoterV2 and choosing the one with the best price; pass feeTier to override. Supports ERC-20 <-> ERC-20, native-in (ETH -> ERC-20), and native-out (ERC-20 -> ETH). Both exact-in and exact-out. Returns an unsigned tx (with a reset+approve chain when the router needs allowance) that send_transaction can forward to Ledger Live. Single-hop only in v1 — multi-hop routes through an intermediate asset (e.g. via WETH) fall back to prepare_swap.

pair_ledger_liveA

Initiate a WalletConnect v2 pairing session with Ledger Live. Returns a URI and ASCII QR code — paste into Ledger Live's WalletConnect screen to complete pairing. The session persists for future transactions. EVM chains only; for TRON use pair_ledger_tron instead.

pair_ledger_tronA

Pair the host's directly-connected Ledger device for TRON signing. REQUIREMENTS: Ledger plugged into the machine running this MCP (USB, not WalletConnect), device unlocked, and the 'Tron' app open on-screen. Ledger Live's WalletConnect relay does not currently honor the tron: CAIP namespace, so TRON signing goes over USB HID via @ledgerhq/hw-app-trx. Reads the device address at m/44'/195'/'/0/0 (default accountIndex=0) and caches it so get_ledger_status can report it. Call multiple times with different accountIndex values (0, 1, 2, …) to pair additional TRON accounts — each call adds to the cache; subsequent calls for the same index refresh in place. Call this once per session (per account) before calling any prepare_tron_* tool or send_transaction with a TRON handle. If the TRON app isn't open, or the device is locked, returns an actionable error describing what to fix.

pair_ledger_solanaA

Pair the host's directly-connected Ledger device for Solana signing. REQUIREMENTS: Ledger plugged into the machine running this MCP (USB, not WalletConnect), device unlocked, and the 'Solana' app open on-screen. Ledger Live's WalletConnect integration does NOT expose Solana accounts, so Solana signing goes over USB HID via @ledgerhq/hw-app-solana (same USB path as TRON). Reads the device address at m/44'/501'/<accountIndex>' (default accountIndex=0 — the first Solana account in Ledger Live) and caches it so get_ledger_status can report it under the solana: [...] section. Call multiple times with different accountIndex values to pair additional Solana accounts. Call this once per session (per account) before prepare_solana_* or send_transaction with a Solana handle. If the Solana app isn't open, the device is locked, or the derivation path doesn't match your Ledger Live setup, returns an actionable error.

pair_ledger_btcA

Pair the host's directly-connected Ledger device for Bitcoin signing. REQUIREMENTS: Ledger plugged in over USB, device unlocked, the 'Bitcoin' app open on-screen. Ledger Live's WalletConnect relay does NOT expose bip122 accounts to dApps, so Bitcoin signing goes over USB HID via @ledgerhq/hw-app-btc (same USB path as Solana / TRON). ONE CALL ENUMERATES ALL FOUR ADDRESS TYPES for the requested accountIndex (default 0): legacy P2PKH (44'/0'/<n>'/0/01...), P2SH-wrapped segwit (49'/0'/<n>'/0/03...), native segwit P2WPKH (84'/0'/<n>'/0/0bc1q...), and taproot P2TR (86'/0'/<n>'/0/0bc1p...). All four are cached so get_ledger_status can report them under the bitcoin: [...] section. Call again with a different accountIndex to expose additional accounts. Read-only on the device — the Ledger BTC app does not prompt during getWalletPublicKey by default. Phase 1 is mainnet-only.

prepare_solana_native_sendA

Build an unsigned SOL native-transfer DRAFT via SystemProgram.transfer. Returns a compact preview + opaque handle — but does NOT yet serialize the message or fetch a blockhash (those happen in preview_solana_send, called right before send_transaction, to keep the ~60s blockhash validity window from being burned during user review). Run pair_ledger_solana once per session first so the Solana app is open and the device address is verified. Amount is in SOL (e.g. "0.5") or "max" for full balance minus fee + safety buffer. Priority fee is added dynamically only when getRecentPrioritizationFees p50 is above the congestion threshold. OPTIONAL MEMO: pass memo: "..." (≤256 UTF-8 bytes) to attach an SPL Memo program instruction (program id MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr) to the tx — common for invoice / payment-reference strings. The Ledger Solana app clear-signs Memo program calls and renders the UTF-8 string on-device alongside the transfer. AUTO NONCE SETUP: if the wallet has no durable-nonce account yet (first Solana send), this tool transparently bundles createAccountWithSeed + nonceInitialize ahead of the transfer in a single tx — costs an extra ~0.00144 SOL rent (reclaimable via prepare_solana_nonce_close), surfaced in the response (firstTimeNonceSetup: "true", rentLamports, description suffix). Subsequent sends are durable-nonce-protected and stay valid indefinitely on the device. The Ledger Solana app clear-signs SystemProgram.transfer + nonce-account ops (no blind-sign hash-match step needed for native sends).

prepare_solana_spl_sendA

Build an unsigned SPL token transfer DRAFT via Token.TransferChecked. Returns a compact preview + opaque handle — but does NOT yet serialize the message or fetch a blockhash. When the user says 'send', call preview_solana_send(handle) to pin a fresh blockhash, compute the Message Hash, and emit the CHECKS agent-task block, then call send_transaction. Run pair_ledger_solana first. Pass the base58 SPL mint address (canonical decimals resolved for USDC, USDT, JUP, BONK, JTO, mSOL, jitoSOL; otherwise read from chain). If the recipient does NOT yet have an Associated Token Account for this mint, the draft automatically includes a createAssociatedTokenAccount instruction — the sender pays ~0.00204 SOL rent, disclosed explicitly (rentLamports + description). AUTO NONCE SETUP: if the wallet has no durable-nonce account yet, this tool transparently bundles createAccountWithSeed + nonceInitialize ahead of the SPL transfer (legacy blockhash; subsequent SPL sends use the durable-nonce path). Surfaced as firstTimeNonceSetup: "true" + ~0.00144 SOL rent in the description. BLIND-SIGN REQUIRED: the Ledger Solana app does NOT auto clear-sign TransferChecked — its parser requires a signed 'Trusted Name' TLV descriptor that only Ledger Live supplies, so the device drops into blind-sign and shows a 'Message Hash' (base58(sha256(messageBytes))). The user must (1) enable 'Allow blind signing' in Solana app → Settings, and (2) match the Message Hash surfaced by preview_solana_send against the on-device value before approving.

prepare_solana_nonce_initA

Explicit one-time setup of a per-wallet durable-nonce account at the deterministic PDA PublicKey.createWithSeed(wallet, 'vaultpilot-nonce-v1', SystemProgram.programId). MOST USERS DO NOT NEED TO CALL THIS DIRECTLY — prepare_solana_native_send / prepare_solana_spl_send auto-bundle the same setup into the user's first send. Use this tool when the user wants the setup standalone (e.g. before a Jupiter swap or MarginFi action, which can't safely auto-bundle due to size + ALT constraints), or to re-init after a prepare_solana_nonce_close. Costs ~0.00144 SOL rent-exempt seed + ~0.000005 SOL tx fee; the rent is fully reclaimable via prepare_solana_nonce_close. Refuses if a nonce account already exists at the derived PDA. This init tx uses a regular recent blockhash (no nonce to use yet — same constraint that makes auto-bundling possible inside native/SPL sends).

prepare_solana_nonce_closeA

Tear down a previously-initialized durable-nonce account and return its full balance (~0.00144 SOL) to the main wallet. ix[0] = SystemProgram.nonceAdvance (self-protecting, same pattern as any durable-nonce-protected send — so this close tx itself won't expire during Ledger review), ix[1] = SystemProgram.nonceWithdraw (drains the balance). After broadcast, subsequent sends from this wallet will refuse until prepare_solana_nonce_init is run again. Refuses if no nonce account exists for the wallet.

get_solana_swap_quoteA

READ-ONLY — fetch a Jupiter v6 swap quote for previewing the route, expected output, slippage, and price impact before committing to a transaction. Parallel to EVM's get_swap_quote (which uses LiFi). Calls the Jupiter aggregator at lite-api.jup.ag/swap/v1/quote, returns the opaque quoteResponse (which must be passed back verbatim to prepare_solana_swap) plus human-facing fields (symbols, amounts with decimals applied, route labels like 'Meteora DLMM' / 'Raydium CLMM', price impact %). Pass raw integer amounts in base units (e.g., '1000000' for 1 USDC). For native SOL, use the wrapped-SOL mint So11111111111111111111111111111111111111112 — Jupiter auto-wraps/unwraps at swap time.

prepare_solana_swapA

Build an unsigned Jupiter-routed swap DRAFT. Takes the quote object returned by get_solana_swap_quote and calls Jupiter's /swap-instructions endpoint to get the deconstructed instruction list, then composes the final v0 tx: [nonceAdvance, ...computeBudget, ...setup, swap, cleanup?, ...other]. DURABLE NONCE REQUIRED — if the wallet hasn't run prepare_solana_nonce_init, this errors pointing to it. Uses v0 VersionedTransaction with Address Lookup Tables (Jupiter routes commonly exceed legacy-tx account limits). Returns a compact preview + opaque handle; NOT yet signable — when the user says 'send', call preview_solana_send(handle) to pin the current nonce value, then send_transaction. BLIND-SIGN REQUIRED on Ledger (Jupiter's program ID isn't in the Solana app's clear-sign registry), so the user must match the Message Hash on-device — surfaced in the CHECKS block emitted by preview_solana_send.

prepare_marginfi_initA

One-time setup: build a tx that creates a deterministic MarginfiAccount PDA under the user's wallet on MarginFi mainnet. Uses marginfi_account_initialize_pda so only the wallet (authority + fee_payer) signs — no ephemeral keypair required, Ledger-compatible. PDA seeds are ["marginfi_account", group, wallet, accountIndex, 0], with accountIndex defaulting to 0. After broadcast, prepare_marginfi_supply / withdraw / borrow / repay for this wallet will use this MarginfiAccount automatically. COST: ~0.01698 SOL rent-exempt minimum (for the 2312-byte PDA) + ~0.000005 SOL tx fee. The rent is PAID FROM THE USER WALLET DIRECTLY (not via an ephemeral keypair) and is reclaimable when the MarginfiAccount is closed. Surface this cost to the user before they approve on Ledger — the blind-sign screen only shows a Message Hash, so the user has no on-device check of the balance delta. DURABLE NONCE REQUIRED: this tx carries ix[0] = nonceAdvance (same pattern as every other Solana send in this server), so the wallet must have run prepare_solana_nonce_init first; otherwise this tool errors with a clear pointer. BLIND-SIGN on Ledger (MarginFi's program ID is not in the Solana app's clear-sign registry) — the user matches the Message Hash on-device after preview_solana_send. Refuses if a MarginfiAccount already exists at the derived PDA.

prepare_marginfi_supplyA

Build an unsigned MarginFi SUPPLY tx for a given bank (by symbol or mint). Supplies the specified amount of the underlying token into the user's MarginfiAccount position in that bank, earning the bank's supply APY. DURABLE NONCE REQUIRED + prepare_marginfi_init must have run first; otherwise this tool errors. Pre-flight: bank-pause check; invalid-mint check (MarginFi only lists a subset of SPL tokens). Uses v0 VersionedTransaction + MarginFi group ALTs for compact wire size. BLIND-SIGN on Ledger — match the Message Hash on-device after preview_solana_send.

prepare_marginfi_withdrawA

Build an unsigned MarginFi WITHDRAW tx. Withdraws the specified amount (or ALL, via withdrawAll: true) from the user's supplied position in the named bank. Pre-flight refuses if the account has zero free collateral (the withdraw would push the health factor below the maintenance threshold — the on-chain tx would revert). DURABLE NONCE + prepare_marginfi_init prerequisites identical to prepare_marginfi_supply. BLIND-SIGN on Ledger.

prepare_marginfi_borrowA

Build an unsigned MarginFi BORROW tx against the user's supplied collateral. Pre-flight refuses if the account has zero free collateral. The SDK computes the required oracle-refresh instructions and the health-factor gate is enforced on-chain — but this tool is the right place to surface a clear error rather than burning SOL on a reverting tx. DURABLE NONCE + prepare_marginfi_init prerequisites identical to prepare_marginfi_supply. BLIND-SIGN on Ledger.

prepare_marginfi_repayA

Build an unsigned MarginFi REPAY tx against outstanding debt in the named bank. Pass repayAll: true to repay the full outstanding debt (also clears the balance slot). DURABLE NONCE + prepare_marginfi_init prerequisites identical to prepare_marginfi_supply. BLIND-SIGN on Ledger.

prepare_marinade_stakeA

Build an unsigned Marinade stake tx: deposit amountSol SOL into Marinade and receive mSOL (Marinade's liquid-staking token). Uses the Marinade SDK's marinade.deposit so the on-chain Authorized signer is the user's wallet — no ephemeral keypair, Ledger-compatible. The mSOL ATA is created automatically on first stake (~0.002 SOL ATA rent, reclaimable). DURABLE NONCE REQUIRED — the wallet must have run prepare_solana_nonce_init first; otherwise this tool errors. BLIND-SIGN on Ledger (Marinade's program is not in the Solana app's clear-sign registry) — match the Message Hash on-device after preview_solana_send.

prepare_jito_stakeA

Build an unsigned Jito stake-pool deposit tx: deposit amountSol SOL into Jito's stake pool and receive jitoSOL (Jito's liquid-staking token). Uses the SPL stake-pool program's raw DepositSol instruction with the user's wallet as the on-chain fundingAccount — no ephemeral keypair, Ledger-compatible. The high-level @solana/spl-stake-pool helper would generate an ephemeral SOL-transfer keypair (incompatible with Ledger-only signing); we hand-build the ix to avoid that. The jitoSOL ATA is created automatically on first stake (~0.002 SOL ATA rent, reclaimable). DURABLE NONCE REQUIRED — wallet must have run prepare_solana_nonce_init first; otherwise this tool errors. BLIND-SIGN on Ledger (the SPL stake-pool program is not in the Solana app's clear-sign registry) — match the Message Hash on-device after preview_solana_send. Unstake (immediate via WithdrawSol or delayed via WithdrawStake) is not yet exposed; tracked as a follow-up.

prepare_marinade_unstake_immediateA

Build an unsigned Marinade IMMEDIATE liquid-unstake tx: burn amountMSol mSOL and receive SOL in the same tx via Marinade's liquidity pool (NOT delayed-unstake / OrderUnstake — that flow returns full SOL after one epoch but requires an ephemeral ticket-account signer the Ledger-only signing model can't provide; tracked as a follow-up). The pool charges a small fee (typically 0.3% — varies with pool depth) in exchange for instant liquidity. DURABLE NONCE REQUIRED + same Ledger signing constraints as prepare_marinade_stake. BLIND-SIGN on Ledger.

list_solana_validatorsA

Read-only validator-ranking helper for prepare_native_stake_delegate. Pulls the stakewiz.com public feed (no API key required) and returns a filtered + sorted list of Solana validators with the columns most relevant to delegation: composite quality score (wizScore), commission, MEV (Jito) status + commission, total APY estimate (inflation + MEV), activated stake, delinquent flag, superminority penalty flag, skip rate, uptime, version, country, and a per-validator stakewiz.com profile URL the user can open in a browser to verify independently. Default filters: excludeDelinquent=true. Default sort: wizScore descending. Default limit: 25 (max 100). USE THIS BEFORE prepare_native_stake_delegate so the agent can surface a small ranked menu instead of forcing the user to leave for stakewiz / validators.app and paste back a vote pubkey. INVARIANT #14 NOTE: this is a HELPER — the MCP is NOT the source of truth. Before delegating, the user MUST (1) open the chosen validator's stakewizUrl in a browser to re-verify activated stake / commission / delinquent status against an authority outside the MCP enumeration, and (2) byte-equality-check the votePubkey in the prepare_native_stake_delegate response against the one confirmed in step 1. The response's notes[] field surfaces these instructions verbatim — pass them through to the user.

prepare_native_stake_delegateA

Build an unsigned native-stake-program tx that creates a fresh stake account at a deterministic address (derived per (wallet, validator) via createAccountWithSeed) and delegates it to the given validator vote account. Funds the stake account with amountSol SOL of active principal PLUS a ~0.00228 SOL rent-exempt seed (reclaimable on full withdraw). Authority is the user's wallet for both staker + withdrawer roles — no separate authority handoff is supported in this server. DURABLE NONCE REQUIRED. Refuses if a stake account already exists at the deterministic address (the user almost certainly meant prepare_native_stake_deactivate / withdraw on the existing position). BLIND-SIGN on Ledger by default — match the Message Hash on-device. To pick a validator, call list_solana_validators first.

prepare_native_stake_deactivateA

Build an unsigned native-stake deactivate tx. Initiates the one-epoch (~2-3 days) cooldown after which the stake becomes withdrawable; the stake earns no rewards during deactivation. Wallet must be the stake account's staker authority. After the cooldown lapses, run prepare_native_stake_withdraw to drain the account (or partial-withdraw to leave it open). DURABLE NONCE REQUIRED + same Ledger blind-sign treatment as prepare_native_stake_delegate. The on-chain stake program reverts if the stake is already deactivating/inactive — the simulation gate catches it.

prepare_native_stake_withdrawA

Build an unsigned native-stake withdraw tx. Pulls amountSol SOL (or 'max' for the full lamport balance) from an inactive stake account back into the wallet. 'max' closes the account and reclaims the rent-exempt seed; partial-withdraw leaves the account open. Stake MUST be inactive (one full epoch after deactivate) — on-chain reverts otherwise; the simulation gate catches it. DURABLE NONCE REQUIRED + same Ledger blind-sign treatment as prepare_native_stake_delegate.

prepare_solana_lifi_swapA

Build an unsigned LiFi-routed swap or bridge with Solana as the source chain. Returns a Solana v0 tx the user signs on Ledger. Two flows share this surface: (1) IN-CHAIN swap when toChain="solana" — LiFi internally routes through Jupiter / Orca / similar; consider prepare_solana_swap (Jupiter direct) as the more direct path for in-chain only. (2) CROSS-CHAIN bridge when toChain is an EVM chain — LiFi aggregates Wormhole, deBridge, Mayan, Allbridge. The Solana source tx confirms first; destination delivery happens after via the bridge protocol (typically 1-15 min). DURABLE NONCE REQUIRED. The builder rejects multi-tx routes (returned by some bridge variants) and multi-signer routes (which would need an ephemeral signer LiFi normally provides via its wallet adapter — Ledger-only signing can't supply it). Reverse direction (EVM → Solana) is not yet wired in this server; track as a follow-up. BLIND-SIGN on Ledger — match the Message Hash on-device after preview_solana_send.

prepare_kamino_init_userA

First-time Kamino setup. Creates the user lookup table + userMetadata PDA + obligation PDA (VanillaObligation, tag 0) on Kamino's main market in a single tx. ONE-TIME — required prerequisite before prepare_kamino_supply / borrow / withdraw / repay. Refuses if userMetadata already exists (use the supply tool directly). Costs ~0.028 SOL total in rent for the three accounts (recoverable via Kamino's account-close flow when fully exiting). DURABLE NONCE REQUIRED. BLIND-SIGN on Ledger — Kamino's program isn't in the Solana app's clear-sign allowlist; match the Message Hash on-device after preview_solana_send.

prepare_kamino_supplyA

Build a Kamino deposit (supply) tx. Refuses if the wallet doesn't have Kamino userMetadata + obligation already initialized — run prepare_kamino_init_user first. Validates that the mint is listed on Kamino's main market; resolves decimals from the reserve's mint metadata so callers pass human amounts ("100" = 100 USDC, "0.5" = 0.5 SOL). DURABLE NONCE REQUIRED + same Ledger blind-sign treatment as prepare_kamino_init_user. The returned tx packs [computeBudget, ATA setup if needed, reserve refresh, obligation refresh, deposit, cleanup] under v0 + Kamino's market ALTs.

prepare_kamino_borrowA

Build a Kamino borrow tx — pulls liquidity from a reserve as debt against the obligation's existing collateral. Refuses if the wallet hasn't run prepare_kamino_init_user; refuses if the mint isn't listed on Kamino's main market. On-chain LTV gate: borrow reverts if it would push the obligation over the reserve's borrowLimit (the simulation gate catches this before signing). DURABLE NONCE REQUIRED + same blind-sign treatment as prepare_kamino_supply.

prepare_kamino_withdrawA

Build a Kamino withdraw tx — pulls liquidity out of a previously-supplied reserve. Refuses with a clear error if the wallet has no deposit in the named reserve. Health-factor gated on-chain: withdraws that would leave the obligation under-collateralized for outstanding debt revert (caught by the simulation gate). DURABLE NONCE REQUIRED + same blind-sign treatment as prepare_kamino_supply.

prepare_kamino_repayA

Build a Kamino repay tx — pays down outstanding debt in the named reserve. Refuses with a clear error if the wallet has no debt in the reserve. The on-chain program clamps repayment at outstanding debt, so over-repaying just doesn't burn the excess (no funds lost). DURABLE NONCE REQUIRED + same blind-sign treatment as prepare_kamino_supply.

get_kamino_positionsA

READ-ONLY — enumerate a Solana wallet's Kamino lending position on the main market. Returns the obligation PDA, per-reserve deposits + borrows (with USD values), totalSuppliedUsd / totalBorrowedUsd / netValueUsd, and a health factor (borrowLiquidationLimit / userTotalBorrowBorrowFactorAdjusted; >1 safe, <1 liquidatable, Infinity when no debt — same convention as Aave / MarginFi). Returns an empty list when the wallet has no Kamino userMetadata (= never used Kamino). Reserve-level pause / freeze flags surface in warnings.

get_btc_balanceA

READ-ONLY — fetch the confirmed + mempool balance for a single Bitcoin mainnet address. Returns sats (raw) and BTC (formatted), separated into confirmed and mempool components, plus the address type (legacy / P2SH / native segwit / taproot) and a tx count. Backed by mempool.space's public API by default; configurable via BITCOIN_INDEXER_URL env var or userConfig.bitcoinIndexerUrl for self-hosted Esplora / Electrs. Phase 1 is mainnet-only (testnet/signet rejected).

get_btc_balancesA

READ-ONLY — multi-address Bitcoin balance fetch (1-20 addresses). Per-address indexer errors are surfaced as errored entries instead of failing the whole call (mirrors how EVM portfolio enumeration handles flaky RPCs). Each successful entry has the same shape as get_btc_balance's output.

get_btc_fee_estimatesA

READ-ONLY — current Bitcoin fee-rate recommendations in sat/vB. Returns five labels: fastestFee (~next block), halfHourFee (~3 blocks), hourFee (~6 blocks), economyFee (~144 blocks / 1 day), and minimumFee (mempool floor). Sourced from mempool.space's /v1/fees/recommended endpoint when available; falls back to per-target estimates from the standard Esplora /fee-estimates for self-hosted indexers.

rescan_btc_accountA

READ-ONLY — refresh the cached on-chain txCount for every paired Bitcoin address under one Ledger account by re-querying the indexer. Pure indexer-side: NO Ledger / USB interaction. Use this after the user has received funds (so a previously-empty cached address now has history) or when the indexer was stale at the original pair_ledger_btc scan time. Updates the persisted cache, so subsequent get_btc_account_balance reflects the refresh without another rescan. Three-state extend signal: needsExtend: true (trailing buffer address on any cached chain has on-chain history — re-run pair_ledger_btc to extend the walked window); unverifiedChains: [...] (tail probe REJECTED for that chain — indeterminate, usually a transient indexer hiccup, re-run rescan_btc_account rather than re-pairing); neither field present → all walked chains confirmed healthy. Indexer fan-out is bounded to BITCOIN_INDEXER_PARALLELISM concurrent requests (default 8) to stay under mempool.space's free-tier rate limits; transient 429s and network errors are retried once internally.

get_btc_account_balanceA

READ-ONLY — sum the on-chain balance across every cached USED address (txCount > 0 at last scan) for one Ledger Bitcoin account index. Walks the pairing cache populated by pair_ledger_btc's BIP44 gap-limit scan, fans out to the indexer for live balances, and returns both the rolled-up totals (confirmed + mempool + total sats / BTC) and a per-address breakdown including type, BIP-32 chain (0=receive, 1=change), and addressIndex. Skips empty cached entries (the trailing fresh-receive addresses) to keep fan-out tight. If the cache is stale (recent receive on a previously-empty cached address), call rescan_btc_account to refresh — pure indexer fetch, no Ledger needed. Only re-run pair_ledger_btc when funds may have landed PAST the originally-walked gap window (the rescan flags that case via needsExtend: true).

get_btc_block_tipA

READ-ONLY — current Bitcoin mainnet chain tip. Returns block height, 64-hex block hash, header timestamp (unix seconds), server-computed ageSeconds (now − timestamp), and — when the indexer exposes them — BIP-113 median time past + difficulty. Backed by the configured indexer (mempool.space default; BITCOIN_INDEXER_URL env var or bitcoinIndexerUrl user-config override for self-hosted Esplora). Useful for: latest-hash lookups, block-age UX context (Bitcoin block intervals are Poisson — a 40-min gap is normal but worth surfacing), indexer-freshness sanity checks before quoting balances, confirmation-depth math against get_btc_tx_history entries.

get_btc_blocks_recentA

READ-ONLY — recent Bitcoin block headers, newest-first (default 144 ≈ one day; capped at 200). Each entry: height, 64-hex hash, header timestamp, tx count, size, weight (when exposed), and — on indexers that surface it (mempool.space) — the mining pool name. Backbone for chain-health questions: 'is the chain producing blocks at the expected rate?', 'any empty blocks recently?', 'who's mining most of the recent window?'. Used internally by get_market_incident_status({ protocol: 'bitcoin' }) to compute hash_cliff, empty_block_streak, and miner_concentration. Issue #233 v1.

get_ltc_block_tipA

READ-ONLY — current Litecoin mainnet chain tip. Mirror of get_btc_block_tip for Litecoin: height, 64-hex hash, timestamp, ageSeconds, optional MTP + difficulty. Backed by the configured indexer (litecoinspace.org default; LITECOIN_INDEXER_URL env var or litecoinIndexerUrl user-config override for self-hosted Esplora). LTC blocks target 2.5 minutes — a 10-min gap is well within Poisson normal but worth surfacing. Issue #233 v1 (this tool was missing from the MCP surface despite the underlying indexer method existing in code).

get_ltc_blocks_recentA

READ-ONLY — recent Litecoin block headers, newest-first (default 144 ≈ 6h at 2.5-min blocks; capped at 200). Mirror of get_btc_blocks_recent for LTC. Used internally by get_market_incident_status({ protocol: 'litecoin' }) to compute hash_cliff, empty_block_streak, and miner_concentration. Issue #233 v1.

get_btc_chain_tipsA

READ-ONLY — bitcoind getchaintips output: every fork the node knows about, with branchlen and status (active / valid-fork / valid-headers / headers-only / invalid). THE primitive for fork / deep-reorg detection — Esplora indexers cannot expose this; they only know the chain they followed. Requires BITCOIN_RPC_URL configured (self-hosted bitcoind or a public RPC provider). Returns available: false with a setup hint when RPC is not configured. Issue #248 / #233 v2.

get_ltc_chain_tipsA

READ-ONLY — litecoind getchaintips output. Mirror of get_btc_chain_tips for LTC. Requires LITECOIN_RPC_URL configured. Self-hosting litecoind -prune=5000 is much cheaper than self-hosting bitcoind (~5GB on disk + ~6h IBD on a residential link), so for LTC users wanting an indexer-independent second opinion, self-hosting is the most accessible route. Issue #248 / #233 v2.

get_btc_block_statsA

READ-ONLY — bitcoind getblockstats(hashOrHeight) output: fee distribution (min / max / avg / 10/25/50/75/90 percentile feerates in sat/vB), tx count, block size, total fees. RPC-only — Esplora exposes block size + tx count but NOT fee percentiles. Used to spot fee-market anomalies and to baseline mempool_anomaly. Requires BITCOIN_RPC_URL configured. Issue #248 / #233 v2.

get_ltc_block_statsA

READ-ONLY — litecoind getblockstats output. Mirror of get_btc_block_stats for LTC. Requires LITECOIN_RPC_URL configured. Issue #248 / #233 v2.

get_btc_mempool_summaryA

READ-ONLY — bitcoind getmempoolinfo output: tx count in mempool, total bytes, memory usage, current minimum admission feerate, total fees of mempool txs. RPC-only — Esplora's mempool view is whatever that one node sees; ours gives us the real local view + the daemon's admission policy. Used by get_market_incident_status to flip the mempool_anomaly signal from available: false to live computation. Requires BITCOIN_RPC_URL configured. Issue #248 / #236 v2.

get_ltc_mempool_summaryA

READ-ONLY — litecoind getmempoolinfo output. Mirror of get_btc_mempool_summary for LTC. Requires LITECOIN_RPC_URL configured. Issue #248 / #236 v2.

get_btc_tx_historyA

READ-ONLY — recent Bitcoin transaction history for a single address (newest-first). Each entry surfaces txid, received/sent sats from this address's perspective, the network fee, block height + time (when confirmed), and an RBF-eligible flag (sequence < 0xFFFFFFFE on at least one input). Default 25 txs, capped at 50 (one Esplora page); pagination beyond is a follow-up.

prepare_btc_sendA

Build an unsigned Bitcoin native-send PSBT (segwit/taproot only in Phase 1). Returns a 15-min handle the agent forwards to send_transaction; the Ledger BTC app clear-signs every output (address + amount) + fee on-screen, so there is NO blind-sign hash to pre-match in chat. The verification block surfaces every output's address, amount in BTC, isChange flag, fee (BTC + sat/vB), and RBF flag. Fee selection: pass feeRateSatPerVb for an explicit sat/vB number, OR feePriority for a fuzzy preset (fastestFee / halfHourFee / hourFee / economyFee / minimumFee — issue #435) that resolves to mempool.space's named buckets at prepare time. Default (neither set) is halfHourFee. The resolved sat/vB always appears in the response under feeRateSatPerVb so the user sees what was picked. Coin-selection runs branch-and-bound + accumulative fallback via the coinselect library; a fee-cap guard refuses any tx whose fee exceeds max(10 × feeRate × vbytes, 2% of total output value) unless allowHighFee: true is passed. RBF is enabled by default (sequence 0xFFFFFFFD); pass rbf: false to mark final.

prepare_btc_lifi_swapA

Build an unsigned Bitcoin PSBT-v0 that bridges native BTC to a token on another chain via LiFi's aggregator. LiFi auctions the route across intent solvers (NEAR Intents, Garden, Thorswap, Chainflip, Symbiosis, …) and returns a PSBT depositing to the chosen solver's vault address with an OP_RETURN memo committing to the cross-chain destination. Destinations: every EVM chain (ethereum/arbitrum/polygon/base/optimism) and Solana — TRON has no LiFi route from BTC and is rejected. Source-side scope (Phase 1, mirrors prepare_btc_send): native segwit and taproot only. Returns a 15-min handle the agent forwards to send_transaction; the Ledger BTC app clear-signs every output (vault deposit + OP_RETURN + change-back-to-source + LiFi fee output) on-screen, so there is NO blind-sign hash to pre-match in chat. The verification block surfaces the vault address, OP_RETURN bytes (hex + ASCII prefix), expected and minimum output on the destination, slippage, the chosen solver, and execution duration estimate. Server-side checks before forwarding: every PSBT input belongs to the source address, exactly one OP_RETURN output is present, the deposit output address matches the LiFi-advertised vault, and nonWitnessUtxo is hydrated on every input (Ledger 2.x rejects segwit/taproot inputs without it).

prepare_btc_rbf_bumpA

Build a BIP-125 Replace-By-Fee replacement for a stuck mempool BTC tx. Reuses the original tx's exact input set, preserves every recipient verbatim, and shrinks the change output to absorb the fee bump. Sequence stays at 0xFFFFFFFD so the replacement is itself RBF-eligible (the user can bump again if the new rate is still too low). Returns a 15-min handle the agent forwards to send_transaction; the Ledger BTC app clear-signs every output + new fee on-screen, so there is NO blind-sign hash to pre-match in chat. Refusal cases: original tx already confirmed; no input is BIP-125-eligible; any input belongs to a wallet other than wallet (multi-source RBF out of scope); no change output (no headroom to absorb the bump — CPFP territory); BIP-125 rule 4 violation (new fee must be >= old fee + 1 sat/vB × new vsize); bumped change below the 546-sat dust threshold; fee exceeds the safety cap (override with allowHighFee: true). Phase 1 source-side scope: native segwit + taproot only.

register_btc_multisig_walletA

One-time registration of a multi-sig Bitcoin wallet policy with the Ledger BTC app (BIP-388 wallet policies). REQUIREMENTS: Ledger plugged in over USB, device unlocked, the 'Bitcoin' app open on-screen. Constructs a wsh(sortedmulti(M,@0/**,@1/**,...)) descriptor from the supplied cosigners, verifies the connected Ledger's master fingerprint matches exactly one cosigner slot, calls Ledger's registerWallet (the device walks every cosigner xpub fingerprint on-screen for verification — the user MUST confirm each fingerprint matches what they expect, since this is the moment that anchors the policy), and persists the descriptor + 32-byte HMAC. The HMAC is reused on every subsequent sign_btc_multisig_psbt call so the user only walks the descriptor approval flow once per setup. Phase 2 scope: P2WSH (wsh) only. Hard-validates every cosigner xpub via @scure/bip32 round-trip — typos that would silently register a wallet we can never sign with are refused up-front.

sign_btc_multisig_psbtA

Co-signer flow — adds OUR Ledger signature to a multi-sig PSBT produced by an external initiator (Sparrow / Specter / Caravan / a peer running this server). Looks up the registered wallet by name, decodes the PSBT, validates every input carries a bip32_derivation entry for our master fingerprint (defense against being tricked into signing for a foreign tx), forwards to the Ledger device for the on-device output walkthrough (the user MUST verify every output address + amount on-device matches the chat-side verification block before approving), splices our partial signature(s) into the PSBT, returns the partial PSBT for the user to share back to the coordinator. We do NOT finalize or broadcast — that's the initiator's job once they have all M signatures. Phase 2 scope: P2WSH wallets registered via register_btc_multisig_wallet.

combine_btc_psbtsA

Merge 2-15 partial PSBTs from multi-sig cosigners into one whose inputs carry every cosigner's signature. Each entry must be a base64-encoded PSBT v0 sharing the same unsigned tx body (same inputs/outputs/sequences/locktime); only per-cosigner witness data may differ. Refuses with a clear error when bodies disagree — combining across distinct unsigned txs would silently merge signatures across different transactions. Returns the merged PSBT plus a per-input signature count so the caller can tell whether the threshold has been reached. No device touch.

finalize_btc_psbtA

Finalize a fully-signed multi-sig PSBT (typically the output of combine_btc_psbts once the threshold is met) and extract the broadcast-ready tx hex. Refuses with a per-input breakdown when any input is below its threshold (e.g. "input 0: 1/2 signatures"). Pass broadcast: true to send via the configured indexer in the same call — returns broadcastedTxid on success. Pass broadcast: false (default) when the caller wants to inspect the hex first or broadcast through a different relay. No device touch.

get_btc_multisig_balanceA

Watch-only balance read for a registered multi-sig wallet. Walks both BIP-32 chains (chain=0 receive, chain=1 change) up to a gap-limit window (default 20, BIP-44 standard), queries each derived address via the configured Esplora indexer, returns the aggregate balance plus per-address breakdown for entries with on-chain history. No device touch — addresses are derived locally from the stored cosigner xpubs. Phase 3 supports P2WSH (wsh) wallets only; taproot lands in a follow-up PR.

get_btc_multisig_utxosA

Return the UTXO set for a registered multi-sig wallet. Same gap-limit walk as get_btc_multisig_balance; each UTXO carries the witnessScript + cosigner pubkeys needed to build a multi-sig PSBT input. Used internally by prepare_btc_multisig_send (initiator flow); also exposed directly for users who want to inspect the spendable set without preparing a tx. No device touch.

prepare_btc_multisig_sendA

Initiator flow — build a tx FROM a registered multi-sig wallet, sign it with our Ledger key in the same call, return the partial PSBT for cosigners to sign. Pipeline: (1) fetch UTXOs across the wallet's gap-limit window, (2) coin-select with a multi-sig-aware vbyte estimator (P2WSH sortedmulti(M,...,N) inputs are ~2-4× P2WPKH), (3) resolve a fresh chain=1 change address (lowest unused index), (4) build PSBT v0 with witnessUtxo + nonWitnessUtxo (Ledger app 2.x requirement) + witnessScript + bip32_derivation for ALL cosigners, (5) sign with our Ledger via the existing co-signer flow (the device walks every output address + amount on-screen), (6) splice our signature into the PSBT, return the partial PSBT. We do NOT finalize or broadcast — the caller gathers remaining signatures externally, then runs combine_btc_psbts + finalize_btc_psbt. The fee-cap guard scales to multi-sig sizes automatically. Phase 3 supports wsh (P2WSH) wallets only; taproot lands in a follow-up PR.

unregister_btc_multisig_walletA

Drop a registered multi-sig wallet from the local cache. The Ledger device retains the policy HMAC indefinitely (no on-device unregister API), so re-registering with the SAME descriptor + cosigners returns the same HMAC the device already has. This tool only forgets the local-disk entry — call it before re-registering with different cosigners under the same name, or to clean up wallets you no longer use. Idempotent: returns removed: false when the name isn't registered. No device touch.

sign_message_btcA

Sign a UTF-8 message with a paired Bitcoin address using the Bitcoin Signed Message format (BIP-137). Returns a base64-encoded compact signature with a header byte that matches the address-type convention (legacy / P2SH-wrapped / native segwit) AND messageSha256 — a lowercase hex SHA-256 of the exact UTF-8 bytes submitted to the device (Inv #8 byte-fingerprint, issue #454). Surface messageSha256 in the verbatim message-sign block so the user can recompute on a separate device (printf '%s' '<message>' | sha256sum) and catch unicode-confusable substitution attacks the Ledger Nano OLED can't show in full. The Ledger BTC app prompts the user to confirm the message text on-device before signing — same clear-sign UX as send-side flows. DRAINER-STRING REFUSAL (issue #454): the MCP refuses messages containing value-transfer / authorization markers (transfer / authorize / grant / custody / release / consent) or explicit drainer templates ("I authorize", "granting full custody", "I consent to", "I hereby transfer", "release my") BEFORE any device interaction — fires regardless of agent cooperation. Legitimate Sign-In-with-Bitcoin / proof-of-funds flows don't use these markers. Taproot (bc1p…) addresses are refused: BIP-322 (taproot's canonical message scheme) is not yet exposed by the Ledger BTC app; sign with one of your other paired address types from the same Ledger account instead.

pair_ledger_ltcA

Pair the host's directly-connected Ledger device for Litecoin signing. REQUIREMENTS: Ledger plugged in over USB, device unlocked, the 'Litecoin' app open on-screen. Ledger Live's WalletConnect relay does not expose Litecoin accounts to dApps, so signing goes over USB HID via @ledgerhq/hw-app-btc (the same SDK as Bitcoin, with currency:'litecoin' selecting Litecoin-specific encoding). One call enumerates the four BIP-44 address types (legacy L…, p2sh-segwit M…, native segwit ltc1q…, taproot ltc1p…) for the given account index. BIP-44 coin_type 2. Per-type fault-tolerant: each address-type walk runs independently, so one type's failure (e.g. the Ledger Litecoin app currently rejects bech32m/taproot with 'Unsupported address format bech32m') does NOT abort the others — the failed type is recorded under skipped[] in the response and the remaining three are paired and persisted. Note: Litecoin Core has not activated Taproot on mainnet, so ltc1p… outputs would not be spendable anyway — taproot pairing is effectively forward-compat only. All paired entries surface under the litecoin: [...] section of get_ledger_status.

get_ltc_balanceA

Return the on-chain balance for one Litecoin mainnet address via the Esplora indexer (litecoinspace.org by default; override via LITECOIN_INDEXER_URL env var or userConfig.litecoinIndexerUrl). Returns confirmed + mempool litoshis and an LTC-decimal projection. Accepts L/M/3/ltc1q/ltc1p — the read path validates format only.

prepare_litecoin_native_sendA

Build an unsigned Litecoin native-send PSBT. Same pipeline as prepare_btc_send: fetch UTXOs + fee rate, run coin-selection, build a PSBT v0 with nonWitnessUtxo populated on every input (Ledger app 2.x requirement). Initial release: source addresses must be native segwit (ltc1q…) or taproot (ltc1p…); recipients can be L/M/ltc1q/ltc1p (legacy 3-prefix P2SH refused on send because bitcoinjs-lib ties the scriptHash byte to a single network object). Returns a handle consumed by send_transaction, which signs over USB HID with the Litecoin app and broadcasts via the indexer.

sign_message_ltcA

Sign a UTF-8 message with a paired Litecoin address using the BIP-137 compact-signature scheme (with Litecoin's \x19Litecoin Signed Message:\n prefix). Returns the signature plus messageSha256 — lowercase hex SHA-256 of the exact UTF-8 bytes submitted to the device (Inv #8 byte-fingerprint, issue #454); surface in the verbatim block so the user can recompute on a separate device. Same on-device clear-sign UX as sign_message_btc. DRAINER-STRING REFUSAL (issue #454): refuses messages containing value-transfer / authorization markers or explicit drainer templates BEFORE any device interaction — same allowlist as sign_message_btc. Taproot (ltc1p…) is refused — BIP-322 isn't exposed by the Ledger Litecoin app.

rescan_ltc_accountA

READ-ONLY — refresh the cached on-chain txCount for every paired Litecoin address under one Ledger account by re-querying the indexer. Pure indexer-side: NO Ledger / USB interaction. Use this after the user has received funds (so a previously-empty cached address now has history) or when the indexer was stale at the original pair_ledger_ltc scan time. Updates the persisted cache, so subsequent get_ltc_balance reflects the refresh without another rescan. Three-state extend signal: needsExtend: true (trailing buffer address on any cached chain has on-chain history — re-run pair_ledger_ltc to extend the walked window); unverifiedChains: [...] (tail probe REJECTED for that chain — indeterminate, usually a transient indexer hiccup, re-run rescan_ltc_account rather than re-pairing); neither field present → all walked chains confirmed healthy. Indexer fan-out is bounded to LITECOIN_INDEXER_PARALLELISM concurrent requests (default 8) to stay under litecoinspace.org's free-tier rate limits; transient 429s and network errors are retried once internally.

prepare_tron_lifi_swapA

Build an unsigned LiFi-routed cross-chain bridge with TRON as the source chain. User signs a TRON tx via Ledger over USB; the bridge protocol delivers tokens on the destination (any EVM chain or Solana) after the source confirms (typically 1-15 min). LiFi aggregates NearIntents, Wormhole, Allbridge, etc. The builder (1) decodes the TRON protobuf to extract the TriggerSmartContract envelope, (2) asserts the contract_address is the LiFi Diamond on TRON (TU3ymitEKCWQFtASkEeHaPb8NfZcJtCHLt) and the owner_address is the user's wallet, (3) decodes the inner ABI calldata's BridgeData tuple and cross-checks destinationChainId + receiver against the user's request — refuses on any mismatch. NEAR Intents routes (intermediate-chain settlement on NEAR's pseudo-chain 1885080386571452) are allowlisted via a hardcoded source-code constant so a hostile aggregator cannot fabricate 'intermediate-chain' encodings; receiver-side checks still apply unchanged. TRC-20 source flows REQUIRE a prior approve to the LiFi Diamond — call prepare_tron_trc20_approve first with spender: "TU3ymitEKCWQFtASkEeHaPb8NfZcJtCHLt" and the amount you intend to swap; insufficient allowance reverts the swap on-chain. BLIND-SIGN on Ledger (LiFi Diamond not in TRON app's clear-sign allowlist) — enable "Allow blind signing" in the on-device Solana app Settings; the device shows the txID, which the user matches against the txID in the prepare receipt. Pair the Ledger via pair_ledger_tron first. Broadcast goes via TronGrid's /wallet/broadcasthex endpoint (LiFi gives us only raw_data_hex, not the deserialized JSON shape /wallet/broadcasttransaction requires).

prepare_sunswap_swapA

Build an unsigned SunSwap V2 same-chain swap on TRON. SunSwap V2 is a Uniswap-V2 fork; this tool routes through the V2 router (TNJVzGqKBWkJxJB5XYSqGAwUTV15U24pPq) using the standard swapExactETHForTokens / swapExactTokensForETH / swapExactTokensForTokens selectors based on which side is native TRX. Path encoding: TRX→TRC20 = [WTRX, toToken]; TRC20→TRX = [fromToken, WTRX]; TRC20→TRC20 = [fromToken, WTRX, toToken]. The builder (1) calls getAmountsOut on the router via /triggerconstantcontract to compute the expected output, (2) derives minOut as quotedOut * (10000 - slippageBps) / 10000, (3) for TRC-20 sources, reads allowance(wallet, router) and refuses with a recovery hint if insufficient — the user must run prepare_tron_trc20_approve(token, spender=router, amount) first, broadcast it, wait ~3s for it to land, then retry. (4) hand-rolls ABI calldata for the swap call (no SDK), (5) hits TronGrid /triggersmartcontract to build the tx, (6) verifies the returned raw_data_hex matches exactly what we asked for (selector + parameter + call_value + fee_limit) and refuses any drift. BLIND-SIGN on Ledger TRON app — the SunSwap router is not in the device's clear-sign allowlist. Enable "Allow blind signing" in the on-device TRON app Settings; the device shows the txID, which the user matches against the txID in the prepare receipt. Pair the Ledger via pair_ledger_tron first. Smart Router (V1+V2+V3+PSM aggregator) is intentionally not used — V2 router only — because Smart Router's mainnet address has not been published officially and its multi-version path encoding is a different ABI shape.

get_solana_setup_statusA

READ-ONLY — probe which one-time setup pieces are already in place for a Solana wallet: the durable-nonce account (exists / address / current nonce value / authority) and the set of MarginfiAccount PDAs (index + address). Call this BEFORE planning a multi-step Solana flow (nonce init → MarginFi init → supply) so agents can skip redundant prepare_* calls instead of re-proposing them and letting the user correct you. Mirrors the get_ledger_status pattern of cheap chain-read setup introspection. One getAccountInfo per probed PDA; no SDK load, no oracle fetch. Returns empty arrays / exists:false when nothing's set up — never throws for an empty wallet.

get_vaultpilot_config_statusA

READ-ONLY — report what the server knows about its local config without revealing any secret values. Returns the config-file path + existence, server version, per-chain RPC URL source classification (env-var / provider-key / custom-url / public-fallback), API-key presence + source per service (Etherscan, 1inch, Safe, TronGrid, WalletConnect — boolean + source enum, never values), counts of paired Ledger accounts (Solana / TRON), the WC session-topic SUFFIX (last 8 chars only — same convention as get_ledger_status), the agent-side preflight-skill install state, a setupHints array (each entry has a kind discriminator: rate-limit nudges surface when a no-key default RPC has been throttled past threshold and tell the user which provider to sign up for + the wizard subcommand; demo-mode nudges fire on a fresh-install state — no keys, no pairings, no custom RPC — suggesting VAULTPILOT_DEMO=true as the zero-friction first-time path per issue #371), AND a demoMode field that surfaces whether VAULTPILOT_DEMO=true is active plus the activation recipe. Pure local I/O — reads ~/.vaultpilot-mcp/config.json + process.env, no RPC calls, no network. Use this when the user asks 'is my config set up correctly' or 'why is my Solana balance read failing' before suggesting they re-run setup or paste keys. AGENT BEHAVIOR for setupHints: when the array is non-empty, surface each entry's message + recommendation to the user as actionable advice (rate-limit hints also carry providers + setupCommand; demo-mode hints carry just message + recommendation, with the env-var recipe inline in recommendation). Unlike suspectedPoisoning (which is noise), setupHints are real remediation paths the user wants to act on. AGENT BEHAVIOR for demoMode: if the user asks 'how do I try this without a Ledger / API keys' or 'is there a demo mode', read demoMode.howToEnable and relay it verbatim. The same field also carries liveMode: { active, personaId, addresses } reflecting whether set_demo_wallet has been called this session — when liveMode.active is true, signing-class tools have been re-enabled in simulation-only mode (broadcast intercepted with a structured envelope). When the user wants the write-flow walkthrough, call get_demo_wallet to surface the persona list, then set_demo_wallet({ persona: "..." }) to upgrade.

get_update_commandA

READ-ONLY — return the recommended upgrade flow for the running install path. Combines (1) process.argv/process.execPath heuristics that classify the install as one of npm-global / npx / bundled-binary / from-source / unknown with (2) cached state from the once-per-session npm-registry version check the server already runs lazily on first tool call. Returns: current (server version), latest (most recent npm registry response, or null if the lazy check hasn't resolved yet), updateAvailable (strict-newer comparator), installPath (detected kind), command (the one-liner to run), restartHint (post-upgrade restart note), and an optional note field that flags caveats (unknown install path → defer to INSTALL.md; unresolved version check → can re-run). AGENT BEHAVIOR: call this when the user asks to upgrade, when the VAULTPILOT NOTICE — Update available block appears and the user wants to act on it, or when the user asks 'how do I update vaultpilot-mcp'. Surface command to the user verbatim — do not execute it autonomously. The detection is a heuristic; if installPath is unknown, ask the user which install path they used. Pure local introspection + cache read; no RPC, no fresh network call (the kickoff already did that). Never throws.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/szhygulin/recon-crypto-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server