@supernova123/defillama-mcp-server 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ Use it with **Claude Desktop**, **Cursor**, **Windsurf**, **Cline**, **Continue*
15
15
  ## Why use this?
16
16
 
17
17
  - **No API key required** — DeFi Llama is a free public API
18
- - **8 built-in tools** — covers the most common DeFi data queries
18
+ - **10 built-in tools** — covers the most common DeFi data queries
19
19
  - **Clean markdown output** — results read naturally in chat
20
20
  - **Rate-limited automatically** — polite 500ms throttle across all endpoints
21
21
 
@@ -26,11 +26,12 @@ Use it with **Claude Desktop**, **Cursor**, **Windsurf**, **Cline**, **Continue*
26
26
  | `search_protocols` | Search DeFi protocols by name — returns top results with TVL, chains, category |
27
27
  | `get_protocol_tvl` | Get detailed TVL breakdown for a specific protocol (chain distribution, history, description) |
28
28
  | `get_tvl_by_chain` | Get total TVL for a specific chain (Ethereum, Arbitrum, Base, Solana, etc.) |
29
- | `get_yields` | Get yield/APY data for lending pools and staking, filter by chain / project / min TVL |
29
+ | `get_yields` | Get yield/APY data for lending pools and staking, filter by chain / project / min TVL, sort by APY or TVL |
30
30
  | `get_stablecoins` | Get stablecoin market cap data and rankings |
31
31
  | `get_bridges` | Get cross-chain bridge TVL and volume data |
32
32
  | `get_dex_volumes` | Get DEX trading volumes across chains |
33
33
  | `get_protocol_fees` | Get protocol fee and revenue data |
34
+ | `get_token_price` | Get current price for any token by CoinGecko ID, symbol, or chain:address (batch lookups) |
34
35
 
35
36
  ## Quick Start
36
37
 
package/dist/index.js CHANGED
@@ -198,8 +198,9 @@ server.tool("get_yields", "Get yield/APY data for lending pools and staking acro
198
198
  project: z.string().optional().describe("Filter by project (e.g. 'Aave', 'Lido', 'Compound')"),
199
199
  min_tvl: z.number().optional().default(1_000_000).describe("Minimum TVL in USD (default $1M)"),
200
200
  min_apy: z.number().optional().default(0).describe("Minimum APY % (default 0)"),
201
+ sort_by: z.enum(["tvl", "apy"]).optional().default("tvl").describe("Sort by 'tvl' (default) or 'apy' (highest APY first)"),
201
202
  limit: z.number().optional().default(20).describe("Max results (default 20)"),
202
- }, async ({ chain, project, min_tvl, min_apy, limit }) => {
203
+ }, async ({ chain, project, min_tvl, min_apy, sort_by, limit }) => {
203
204
  try {
204
205
  const data = await rateLimitedFetch(`${YIELDS_BASE}/pools`);
205
206
  if (!data || !Array.isArray(data.data)) {
@@ -221,7 +222,11 @@ server.tool("get_yields", "Get yield/APY data for lending pools and staking acro
221
222
  return false;
222
223
  return true;
223
224
  })
224
- .sort((a, b) => (b.tvlUsd || 0) - (a.tvlUsd || 0))
225
+ .sort((a, b) => {
226
+ if (sort_by === "apy")
227
+ return (b.apy || 0) - (a.apy || 0);
228
+ return (b.tvlUsd || 0) - (a.tvlUsd || 0);
229
+ })
225
230
  .slice(0, limit);
226
231
  if (matches.length === 0) {
227
232
  return { content: [{ type: "text", text: `No yield pools matched (chain: ${chain || "any"}, project: ${project || "any"}, min TVL $${min_tvl.toLocaleString()}, min APY ${min_apy}%).` }] };
@@ -401,6 +406,42 @@ server.tool("get_protocol_fees", "Get protocol fee and revenue data — protocol
401
406
  return { content: [{ type: "text", text: `Error: ${e.message}` }] };
402
407
  }
403
408
  });
409
+ // ── Tool: get_token_price ──
410
+ server.tool("get_token_price", "Get current price for any token by CoinGecko ID, symbol, or chain:address format. Supports batch lookups.", {
411
+ tokens: z.array(z.string()).describe("Token identifiers — CoinGecko IDs (e.g. 'ethereum', 'bitcoin'), symbols (e.g. 'ETH', 'BTC'), or chain:address (e.g. 'ethereum:0x...')"),
412
+ }, async ({ tokens }) => {
413
+ try {
414
+ // DeFi Llama prices API uses "coingecko:id" or "chain:address" format
415
+ const coinIds = tokens.map((t) => {
416
+ if (t.includes(":"))
417
+ return t; // Already chain:address format
418
+ // Treat as CoinGecko ID or symbol
419
+ if (t.startsWith("0x"))
420
+ return `ethereum:${t}`;
421
+ return `coingecko:${t.toLowerCase()}`;
422
+ });
423
+ const url = `https://coins.llama.fi/prices/current/${coinIds.join(",")}`;
424
+ const data = await rateLimitedFetch(url);
425
+ if (!data || !data.coins) {
426
+ return { content: [{ type: "text", text: "No price data returned." }] };
427
+ }
428
+ const lines = Object.entries(data.coins).map(([id, info]) => {
429
+ const price = info.price != null ? `$${info.price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}` : "N/A";
430
+ const symbol = info.symbol || "?";
431
+ const confidence = info.confidence != null ? ` (${Math.round(info.confidence * 100)}% conf)` : "";
432
+ return `- **${symbol}** (${id}) — ${price}${confidence}`;
433
+ });
434
+ return {
435
+ content: [{
436
+ type: "text",
437
+ text: `**Token Prices:**\n\n${lines.join("\n")}`,
438
+ }],
439
+ };
440
+ }
441
+ catch (e) {
442
+ return { content: [{ type: "text", text: `Error: ${e.message}` }] };
443
+ }
444
+ });
404
445
  // Start server
405
446
  async function main() {
406
447
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supernova123/defillama-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for DeFi Llama \u2014 free DeFi TVL, yields, stablecoins, bridges, DEX, and fee data for AI assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -48,4 +48,4 @@
48
48
  "publishConfig": {
49
49
  "access": "public"
50
50
  }
51
- }
51
+ }
package/server.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.friendlygeorge/defillama-mcp-server",
4
+ "description": "MCP server for DeFi Llama \u2014 free DeFi TVL, yields, stablecoins, bridges, DEX, and fee data for AI...",
5
+ "repository": {
6
+ "url": "https://github.com/friendlygeorge/defillama-mcp-server",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "@supernova123/defillama-mcp-server",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ },
18
+ "environmentVariables": [
19
+ {
20
+ "description": "Your API key for the service",
21
+ "isRequired": true,
22
+ "format": "string",
23
+ "isSecret": true,
24
+ "name": "YOUR_API_KEY"
25
+ }
26
+ ]
27
+ }
28
+ ]
29
+ }
package/src/index.ts CHANGED
@@ -236,9 +236,10 @@ server.tool(
236
236
  project: z.string().optional().describe("Filter by project (e.g. 'Aave', 'Lido', 'Compound')"),
237
237
  min_tvl: z.number().optional().default(1_000_000).describe("Minimum TVL in USD (default $1M)"),
238
238
  min_apy: z.number().optional().default(0).describe("Minimum APY % (default 0)"),
239
+ sort_by: z.enum(["tvl", "apy"]).optional().default("tvl").describe("Sort by 'tvl' (default) or 'apy' (highest APY first)"),
239
240
  limit: z.number().optional().default(20).describe("Max results (default 20)"),
240
241
  },
241
- async ({ chain, project, min_tvl, min_apy, limit }) => {
242
+ async ({ chain, project, min_tvl, min_apy, sort_by, limit }) => {
242
243
  try {
243
244
  const data = await rateLimitedFetch(`${YIELDS_BASE}/pools`);
244
245
  if (!data || !Array.isArray(data.data)) {
@@ -257,7 +258,10 @@ server.tool(
257
258
  if (projectFilter && !(p.project || "").toLowerCase().includes(projectFilter)) return false;
258
259
  return true;
259
260
  })
260
- .sort((a: any, b: any) => (b.tvlUsd || 0) - (a.tvlUsd || 0))
261
+ .sort((a: any, b: any) => {
262
+ if (sort_by === "apy") return (b.apy || 0) - (a.apy || 0);
263
+ return (b.tvlUsd || 0) - (a.tvlUsd || 0);
264
+ })
261
265
  .slice(0, limit);
262
266
 
263
267
  if (matches.length === 0) {
@@ -472,6 +476,49 @@ server.tool(
472
476
  }
473
477
  );
474
478
 
479
+ // ── Tool: get_token_price ──
480
+ server.tool(
481
+ "get_token_price",
482
+ "Get current price for any token by CoinGecko ID, symbol, or chain:address format. Supports batch lookups.",
483
+ {
484
+ tokens: z.array(z.string()).describe("Token identifiers — CoinGecko IDs (e.g. 'ethereum', 'bitcoin'), symbols (e.g. 'ETH', 'BTC'), or chain:address (e.g. 'ethereum:0x...')"),
485
+ },
486
+ async ({ tokens }) => {
487
+ try {
488
+ // DeFi Llama prices API uses "coingecko:id" or "chain:address" format
489
+ const coinIds = tokens.map((t: string) => {
490
+ if (t.includes(":")) return t; // Already chain:address format
491
+ // Treat as CoinGecko ID or symbol
492
+ if (t.startsWith("0x")) return `ethereum:${t}`;
493
+ return `coingecko:${t.toLowerCase()}`;
494
+ });
495
+
496
+ const url = `https://coins.llama.fi/prices/current/${coinIds.join(",")}`;
497
+ const data = await rateLimitedFetch(url);
498
+
499
+ if (!data || !data.coins) {
500
+ return { content: [{ type: "text" as const, text: "No price data returned." }] };
501
+ }
502
+
503
+ const lines = Object.entries(data.coins).map(([id, info]: [string, any]) => {
504
+ const price = info.price != null ? `$${info.price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}` : "N/A";
505
+ const symbol = info.symbol || "?";
506
+ const confidence = info.confidence != null ? ` (${Math.round(info.confidence * 100)}% conf)` : "";
507
+ return `- **${symbol}** (${id}) — ${price}${confidence}`;
508
+ });
509
+
510
+ return {
511
+ content: [{
512
+ type: "text" as const,
513
+ text: `**Token Prices:**\n\n${lines.join("\n")}`,
514
+ }],
515
+ };
516
+ } catch (e: any) {
517
+ return { content: [{ type: "text" as const, text: `Error: ${e.message}` }] };
518
+ }
519
+ }
520
+ );
521
+
475
522
  // Start server
476
523
  async function main() {
477
524
  const transport = new StdioServerTransport();