compare_vaults
Compare DeFi vaults side-by-side on TVL, APR, risk scores, audit status, and other key metrics to evaluate investment options.
Instructions
Compare 2-3 DeFi vaults side-by-side on TVL, APR, risk score, risk tier, audited status, and more.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vaults | Yes | Array of 2-3 vaults to compare |
Implementation Reference
- src/tools/compare-vaults.ts:6-61 (handler)Main handler implementation for the compare_vaults tool. Contains the registration and async handler that fetches vault data using Promise.allSettled, handles errors, formats the comparison using formatVaultComparison, and returns the results as text content.
export function registerCompareVaults(server: McpServer) { server.tool( 'compare_vaults', 'Compare 2-3 DeFi vaults side-by-side on TVL, APR, risk score, risk tier, audited status, and more.', { vaults: z .array( z.object({ network: z.string().describe('Network slug (e.g. ethereum, base)'), address: z.string().describe('Vault contract address (0x...)'), }) ) .min(2) .max(3) .describe('Array of 2-3 vaults to compare'), }, async (params) => { const settled = await Promise.allSettled( params.vaults.map((v) => apiGet<{ data: any }>(`/v1/vault/${v.network}/${v.address}`)) ); const errors: string[] = []; const vaultData: any[] = []; settled.forEach((result, i) => { if (result.status === 'fulfilled') { vaultData.push(result.value.data); } else { errors.push( `${params.vaults[i].network}/${params.vaults[i].address}: ${result.reason?.message || 'Unknown error'}` ); } }); if (vaultData.length < 2) { const errorList = errors.length ? `\n\nErrors:\n${errors.map((e) => `- ${e}`).join('\n')}` : ''; return { content: [ { type: 'text' as const, text: `Need at least 2 vaults to compare, but only ${vaultData.length} could be fetched.${errorList}`, }, ], }; } let text = formatVaultComparison(vaultData); if (errors.length) { text += `\n\n**Note:** Could not fetch: ${errors.join('; ')}`; } return { content: [{ type: 'text' as const, text }] }; } ); } - src/tools/compare-vaults.ts:11-20 (schema)Input schema definition using Zod. Validates an array of 2-3 vaults, each with a 'network' slug and 'address' field.
vaults: z .array( z.object({ network: z.string().describe('Network slug (e.g. ethereum, base)'), address: z.string().describe('Vault contract address (0x...)'), }) ) .min(2) .max(3) .describe('Array of 2-3 vaults to compare'), - src/server.ts:7-7 (registration)Import statement for registerCompareVaults function.
import { registerCompareVaults } from './tools/compare-vaults'; - src/server.ts:34-34 (registration)Tool registration call that registers the compare_vaults tool with the MCP server.
registerCompareVaults(server); - src/lib/formatters.ts:70-98 (helper)Helper function formatVaultComparison that formats vault comparison data into a markdown table, including metrics like protocol, chain, asset, TVL, APR, risk score, risk tier, and audit status.
export function formatVaultComparison(vaults: any[]): string { const headers = ['Metric', ...vaults.map((v) => v.vault?.name || v.name || 'Unknown')]; const rows = [ ['Protocol', ...vaults.map((v) => (v.vault || v).protocol_name)], ['Chain', ...vaults.map((v) => (v.vault || v).chain_name)], ['Asset', ...vaults.map((v) => (v.vault || v).asset_symbol || 'N/A')], ['TVL', ...vaults.map((v) => '$' + formatNumber((v.vault || v).tvl_usd))], ['APR', ...vaults.map((v) => formatPercent((v.vault || v).apr_net))], ['APR (7d avg)', ...vaults.map((v) => formatPercent(computeAvgApr(v.snapshots, 7)))], ['APR (30d avg)', ...vaults.map((v) => formatPercent(computeAvgApr(v.snapshots, 30)))], [ 'Risk Score', ...vaults.map((v) => { const d = v.vault || v; return `${d.total_score ?? d.risk_score ?? 'N/A'}/10`; }), ], [ 'Risk Tier', ...vaults.map((v) => { const d = v.vault || v; return d.risk_tier || 'N/A'; }), ], ['Audited', ...vaults.map((v) => ((v.vault || v).is_audited ? 'Yes' : 'No'))], ]; return formatMarkdownTable(headers, rows); }