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); }