UNPKG

realtime-crypto-mcp-server

Version:

A real-time cryptocurrency data provider for Model Context Protocol (MCP) servers. This package integrates with the CoinCap API to provide cryptocurrency exchange details and current rates.

99 lines (98 loc) 3.65 kB
import { z } from "zod"; const COINCAP_API_BASE = "https://api.coincap.io/v2"; // Make API request to CoinCap with rate limiting and retries async function makeCoinCapRequest(url) { const USER_AGENT = "realtime-crypto-app/1.0"; const MAX_RETRIES = 3; const RETRY_DELAY = 1000; // 1 second const headers = { "User-Agent": USER_AGENT, Accept: "application/json", }; let retries = 0; while (retries <= MAX_RETRIES) { try { const response = await fetch(url, { headers }); if (response.status === 429) { // Rate limited - wait and retry retries++; console.log(`Rate limited by CoinCap API. Retry attempt ${retries}/${MAX_RETRIES} after ${RETRY_DELAY}ms delay`); if (retries <= MAX_RETRIES) { await new Promise(resolve => setTimeout(resolve, RETRY_DELAY * retries)); continue; } else { throw new Error("Rate limit exceeded. Maximum retries reached."); } } if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return (await response.json()); } catch (error) { if (retries >= MAX_RETRIES || (error instanceof Error && !error.message.includes("429"))) { console.error("Error making CoinCap request:", error); return null; } retries++; await new Promise(resolve => setTimeout(resolve, RETRY_DELAY * retries)); } } return null; } // Format rate details function formatRateDetails(data) { return [ `Symbol: ${data.symbol || "Unknown"} ${data.currencySymbol || ""}`, `Type: ${data.type || "Unknown"}`, `USD Rate: $${parseFloat(data.rateUsd).toLocaleString(undefined, { maximumFractionDigits: 2 })}`, ].join("\n"); } // Tool definition for "get-rates" export const getRatesTool = { name: "get-rates", description: "Get exchange rates for a cryptocurrency", inputSchema: z.object({ currency: z.string().describe("Cryptocurrency ID (e.g., bitcoin, ethereum, litecoin)"), }).shape, execute: async (args, extra) => { try { const currencyId = args.currency.toLowerCase(); const rateUrl = `${COINCAP_API_BASE}/rates/${currencyId}`; const rateData = await makeCoinCapRequest(rateUrl); if (!rateData || !rateData.data) { return { content: [ { type: "text", text: `Failed to retrieve rates for currency: ${currencyId}`, }, ], }; } const formattedDetails = formatRateDetails(rateData.data); const rateText = `Current rate for ${rateData.data.id}:\n\n${formattedDetails}`; return { content: [ { type: "text", text: rateText, }, ], }; } catch (error) { console.error("Error in getRatesTool.execute:", error); return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }, };