Skip to main content
Glama

CoinGecko API Server MCP

server.js26 kB
const express = require('express'); const { CoinGeckoClient } = require('coingecko-api-v3'); require('dotenv').config(); // Load environment variables from .env file // Import the JSON-RPC middleware const jsonRpcMiddleware = require('./mcp'); // Import MCP schemas const mcpSchemas = require('./mcp-schema'); // Initialize Express const app = express(); const port = process.env.PORT || 3000; // Initialize CoinGecko API client const client = new CoinGeckoClient({ timeout: 10000, autoRetry: true, apiKey: process.env.COINGECKO_API_KEY }); // Middleware app.use(express.json()); // JSON-RPC endpoint for MCP app.post('/rpc', jsonRpcMiddleware); // MCP Schema endpoint app.get('/mcp/schema', (req, res) => { res.json(mcpSchemas); }); // Basic health check route app.get('/', async (req, res) => { res.json({ message: 'CoinGecko API Server is running' }); }); // PING endpoint - Check API server status app.get('/api/ping', async (req, res) => { try { const apiKey = process.env.COINGECKO_API_KEY; const baseUrl = apiKey ? 'https://pro-api.coingecko.com/api/v3/ping' : 'https://api.coingecko.com/api/v3/ping'; if (!apiKey) { console.log('No API key found, using free CoinGecko API for ping'); } const headers = apiKey ? { 'x-cg-pro-api-key': apiKey } : {}; const response = await fetch(baseUrl, { headers }); if (!response.ok) { throw new Error(`Error from CoinGecko API: ${response.status} ${response.statusText}`); } const data = await response.json(); res.json(data); } catch (error) { console.error('Error pinging server:', error); res.status(500).json({ error: 'Failed to ping server' }); } }); // === SIMPLE Endpoints === // Get price data for specific coins app.get('/api/simple/price', async (req, res) => { try { const { ids, vs_currencies } = req.query; if (!ids || !vs_currencies) { return res.status(400).json({ error: 'Missing required parameters: ids and vs_currencies are required' }); } const params = new URLSearchParams(); params.append('ids', ids); params.append('vs_currencies', vs_currencies); // Optional parameters if (req.query.include_market_cap) params.append('include_market_cap', req.query.include_market_cap); if (req.query.include_24hr_vol) params.append('include_24hr_vol', req.query.include_24hr_vol); if (req.query.include_24hr_change) params.append('include_24hr_change', req.query.include_24hr_change); if (req.query.include_last_updated_at) params.append('include_last_updated_at', req.query.include_last_updated_at); if (req.query.precision) params.append('precision', req.query.precision); const apiKey = process.env.COINGECKO_API_KEY; const baseUrl = apiKey ? 'https://pro-api.coingecko.com/api/v3/simple/price' : 'https://api.coingecko.com/api/v3/simple/price'; if (!apiKey) { console.log('No API key found, using free CoinGecko API for simple/price'); } const url = `${baseUrl}?${params.toString()}`; const headers = apiKey ? { 'x-cg-pro-api-key': apiKey } : {}; const response = await fetch(url, { headers }); if (!response.ok) { throw new Error(`Error from CoinGecko API: ${response.status} ${response.statusText}`); } const data = await response.json(); res.json(data); } catch (error) { console.error('Error fetching price data:', error); res.status(500).json({ error: 'Failed to fetch price data' }); } }); // Get token price by contract address app.get('/api/simple/token_price/:id', async (req, res) => { try { const { id } = req.params; const { contract_addresses, vs_currencies, include_market_cap, include_24hr_vol, include_24hr_change, include_last_updated_at, precision } = req.query; if (!contract_addresses || !vs_currencies) { return res.status(400).json({ error: 'Missing required parameters: contract_addresses, vs_currencies' }); } const tokenPriceData = await client.simpleTokenPrice({ id, contract_addresses: contract_addresses.split(','), vs_currencies: vs_currencies.split(','), include_market_cap: include_market_cap === 'true', include_24hr_vol: include_24hr_vol === 'true', include_24hr_change: include_24hr_change === 'true', include_last_updated_at: include_last_updated_at === 'true', precision: precision }); res.json(tokenPriceData); } catch (error) { console.error('Error fetching token price data:', error); res.status(500).json({ error: 'Failed to fetch token price data' }); } }); // Get supported vs currencies app.get('/api/simple/supported_vs_currencies', async (req, res) => { try { // Use Pro API if API key is available, otherwise use free API const apiKey = process.env.COINGECKO_API_KEY; let url; if (apiKey && apiKey !== 'your_api_key_here') { // Pro API url = `https://pro-api.coingecko.com/api/v3/simple/supported_vs_currencies?x_cg_pro_api_key=${apiKey}`; } else { // Free API - fallback for development console.log('Using free CoinGecko API (no API key provided)'); url = 'https://api.coingecko.com/api/v3/simple/supported_vs_currencies'; } const response = await fetch(url); if (!response.ok) { throw new Error(`CoinGecko API responded with status: ${response.status}`); } const supportedVsCurrencies = await response.json(); res.json(supportedVsCurrencies); } catch (error) { console.error('Error fetching supported vs currencies:', error); res.status(500).json({ error: 'Failed to fetch supported vs currencies' }); } }); // === COINS Endpoints === // Get list of all coins app.get('/api/coins/list', async (req, res) => { try { const { include_platform } = req.query; const coinsList = await client.coinList({ include_platform: include_platform === 'true' }); res.json(coinsList); } catch (error) { console.error('Error fetching coins list:', error); res.status(500).json({ error: 'Failed to fetch coins list' }); } }); // Get market data for coins app.get('/api/coins/markets', async (req, res) => { try { const { vs_currency, ids, category, order, per_page, page, sparkline, price_change_percentage } = req.query; if (!vs_currency) { return res.status(400).json({ error: 'Missing required parameter: vs_currency' }); } // Create parameters object const params = new URLSearchParams({ vs_currency, ...(ids && { ids }), ...(category && { category }), ...(order && { order }), per_page: per_page || 100, page: page || 1, ...(sparkline && { sparkline: sparkline === 'true' }), ...(price_change_percentage && { price_change_percentage }) }); // Use Pro API if API key is available, otherwise use free API const apiKey = process.env.COINGECKO_API_KEY; let url; if (apiKey && apiKey !== 'your_api_key_here') { // Pro API params.append('x_cg_pro_api_key', apiKey); url = `https://pro-api.coingecko.com/api/v3/coins/markets?${params.toString()}`; } else { // Free API - fallback for development console.log('Using free CoinGecko API (no API key provided)'); url = `https://api.coingecko.com/api/v3/coins/markets?${params.toString()}`; } const response = await fetch(url); if (!response.ok) { throw new Error(`CoinGecko API responded with status: ${response.status}`); } const marketsData = await response.json(); res.json(marketsData); } catch (error) { console.error("Error fetching coin markets data:", error); res.status(500).json({ error: 'Failed to fetch coin markets data' }); } }); // Get coin details app.get('/api/coins/:coinId', async (req, res) => { try { const { coinId } = req.params; const { localization, tickers, market_data, community_data, developer_data, sparkline } = req.query; const coinData = await client.coinId({ id: coinId, localization: localization !== 'false', tickers: tickers !== 'false', market_data: market_data !== 'false', community_data: community_data !== 'false', developer_data: developer_data !== 'false', sparkline: sparkline === 'true' }); res.json(coinData); } catch (error) { console.error(`Error fetching data for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch data for coin ${req.params.coinId}` }); } }); // Get coin tickers app.get('/api/coins/:coinId/tickers', async (req, res) => { try { const { coinId } = req.params; const { exchange_ids, include_exchange_logo, page, order, depth } = req.query; const tickersData = await client.coinIdTickers({ id: coinId, exchange_ids: exchange_ids ? exchange_ids.split(',') : undefined, include_exchange_logo: include_exchange_logo === 'true', page: page ? parseInt(page) : 1, order, depth: depth === 'true' }); res.json(tickersData); } catch (error) { console.error(`Error fetching tickers for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch tickers for coin ${req.params.coinId}` }); } }); // Get coin history app.get('/api/coins/:coinId/history', async (req, res) => { try { const { coinId } = req.params; const { date, localization } = req.query; if (!date) { return res.status(400).json({ error: 'Missing required parameter: date (format: dd-mm-yyyy)' }); } const historyData = await client.coinIdHistory({ id: coinId, date, localization: localization !== 'false' }); res.json(historyData); } catch (error) { console.error(`Error fetching history for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch history for coin ${req.params.coinId}` }); } }); // Get coin market chart app.get('/api/coins/:coinId/market_chart', async (req, res) => { try { const { coinId } = req.params; const { vs_currency, days, interval, precision } = req.query; if (!vs_currency || !days) { return res.status(400).json({ error: 'Missing required parameters: vs_currency, days' }); } const chartData = await client.coinIdMarketChart({ id: coinId, vs_currency, days, interval, precision }); res.json(chartData); } catch (error) { console.error(`Error fetching market chart for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch market chart for coin ${req.params.coinId}` }); } }); // Get coin market chart range app.get('/api/coins/:coinId/market_chart/range', async (req, res) => { try { const { coinId } = req.params; const { vs_currency, from, to, precision } = req.query; if (!vs_currency || !from || !to) { return res.status(400).json({ error: 'Missing required parameters: vs_currency, from, to' }); } const chartRangeData = await client.coinIdMarketChartRange({ id: coinId, vs_currency, from, to, precision }); res.json(chartRangeData); } catch (error) { console.error(`Error fetching market chart range for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch market chart range for coin ${req.params.coinId}` }); } }); // Get coin OHLC data app.get('/api/coins/:coinId/ohlc', async (req, res) => { try { const { coinId } = req.params; const { vs_currency, days, precision } = req.query; if (!vs_currency || !days) { return res.status(400).json({ error: 'Missing required parameters: vs_currency, days' }); } const ohlcData = await client.coinIdOHLC({ id: coinId, vs_currency, days, precision }); res.json(ohlcData); } catch (error) { console.error(`Error fetching OHLC data for coin ${req.params.coinId}:`, error); res.status(500).json({ error: `Failed to fetch OHLC data for coin ${req.params.coinId}` }); } }); // === CONTRACT Endpoints === // Get coin info from contract address app.get('/api/coins/:assetPlatformId/contract/:contractAddress', async (req, res) => { try { const { assetPlatformId, contractAddress } = req.params; const contractData = await client.contract({ id: assetPlatformId, contract_address: contractAddress }); res.json(contractData); } catch (error) { console.error(`Error fetching contract data:`, error); res.status(500).json({ error: 'Failed to fetch contract data' }); } }); // Get contract market chart app.get('/api/coins/:assetPlatformId/contract/:contractAddress/market_chart', async (req, res) => { try { const { assetPlatformId, contractAddress } = req.params; const { vs_currency, days, precision } = req.query; if (!vs_currency || !days) { return res.status(400).json({ error: 'Missing required parameters: vs_currency, days' }); } const contractChartData = await client.contractMarketChart({ id: assetPlatformId, contract_address: contractAddress, vs_currency, days, precision }); res.json(contractChartData); } catch (error) { console.error(`Error fetching contract market chart data:`, error); res.status(500).json({ error: 'Failed to fetch contract market chart data' }); } }); // Get contract market chart range app.get('/api/coins/:assetPlatformId/contract/:contractAddress/market_chart/range', async (req, res) => { try { const { assetPlatformId, contractAddress } = req.params; const { vs_currency, from, to, precision } = req.query; if (!vs_currency || !from || !to) { return res.status(400).json({ error: 'Missing required parameters: vs_currency, from, to' }); } const contractChartRangeData = await client.contractMarketChartRange({ id: assetPlatformId, contract_address: contractAddress, vs_currency, from, to, precision }); res.json(contractChartRangeData); } catch (error) { console.error(`Error fetching contract market chart range data:`, error); res.status(500).json({ error: 'Failed to fetch contract market chart range data' }); } }); // === ASSET PLATFORMS Endpoint === // Get list of all asset platforms app.get('/api/asset_platforms', async (req, res) => { try { const { filter } = req.query; const assetPlatforms = await client.assetPlatforms({ filter }); res.json(assetPlatforms); } catch (error) { console.error('Error fetching asset platforms:', error); res.status(500).json({ error: 'Failed to fetch asset platforms' }); } }); // === CATEGORIES Endpoints === // Get list of all categories app.get('/api/coins/categories/list', async (req, res) => { try { const categoriesList = await client.coinCategoriesList(); res.json(categoriesList); } catch (error) { console.error('Error fetching categories list:', error); res.status(500).json({ error: 'Failed to fetch categories list' }); } }); // Get list of all categories with market data app.get('/api/coins/categories', async (req, res) => { try { const { order } = req.query; const categories = await client.coinCategories({ order }); res.json(categories); } catch (error) { console.error('Error fetching categories:', error); res.status(500).json({ error: 'Failed to fetch categories' }); } }); // === EXCHANGES Endpoints === // Get list of all exchanges app.get('/api/exchanges', async (req, res) => { try { const { per_page, page } = req.query; const exchanges = await client.exchanges({ per_page: per_page ? parseInt(per_page) : 100, page: page ? parseInt(page) : 1 }); res.json(exchanges); } catch (error) { console.error('Error fetching exchanges:', error); res.status(500).json({ error: 'Failed to fetch exchanges' }); } }); // Get list of all exchanges with IDs app.get('/api/exchanges/list', async (req, res) => { try { const exchangesList = await client.exchangesList(); res.json(exchangesList); } catch (error) { console.error('Error fetching exchanges list:', error); res.status(500).json({ error: 'Failed to fetch exchanges list' }); } }); // Get exchange details app.get('/api/exchanges/:exchangeId', async (req, res) => { try { const { exchangeId } = req.params; const exchangeData = await client.exchangeId({ id: exchangeId }); res.json(exchangeData); } catch (error) { console.error(`Error fetching data for exchange ${req.params.exchangeId}:`, error); res.status(500).json({ error: `Failed to fetch data for exchange ${req.params.exchangeId}` }); } }); // Get exchange tickers app.get('/api/exchanges/:exchangeId/tickers', async (req, res) => { try { const { exchangeId } = req.params; const { coin_ids, include_exchange_logo, page, depth, order } = req.query; const exchangeTickersData = await client.exchangeIdTickers({ id: exchangeId, coin_ids: coin_ids ? coin_ids.split(',') : undefined, include_exchange_logo: include_exchange_logo === 'true', page: page ? parseInt(page) : 1, depth: depth === 'true', order }); res.json(exchangeTickersData); } catch (error) { console.error(`Error fetching tickers for exchange ${req.params.exchangeId}:`, error); res.status(500).json({ error: `Failed to fetch tickers for exchange ${req.params.exchangeId}` }); } }); // Get exchange volume chart app.get('/api/exchanges/:exchangeId/volume_chart', async (req, res) => { try { const { exchangeId } = req.params; const { days } = req.query; if (!days) { return res.status(400).json({ error: 'Missing required parameter: days' }); } const exchangeVolumeChartData = await client.exchangeIdVolumeChart({ id: exchangeId, days: parseInt(days) }); res.json(exchangeVolumeChartData); } catch (error) { console.error(`Error fetching volume chart for exchange ${req.params.exchangeId}:`, error); res.status(500).json({ error: `Failed to fetch volume chart for exchange ${req.params.exchangeId}` }); } }); // === DERIVATIVES Endpoints === // Get all derivative tickers app.get('/api/derivatives', async (req, res) => { try { const derivativesData = await client.derivatives(); res.json(derivativesData); } catch (error) { console.error('Error fetching derivatives:', error); res.status(500).json({ error: 'Failed to fetch derivatives' }); } }); // Get all derivative exchanges app.get('/api/derivatives/exchanges', async (req, res) => { try { const { order, per_page, page } = req.query; const derivativeExchangesData = await client.derivativesExchanges({ order, per_page: per_page ? parseInt(per_page) : undefined, page: page ? parseInt(page) : undefined }); res.json(derivativeExchangesData); } catch (error) { console.error('Error fetching derivative exchanges:', error); res.status(500).json({ error: 'Failed to fetch derivative exchanges' }); } }); // Get derivative exchange data app.get('/api/derivatives/exchanges/:exchangeId', async (req, res) => { try { const { exchangeId } = req.params; const { include_tickers } = req.query; const derivativeExchangeData = await client.derivativesExchangesId({ id: exchangeId, include_tickers }); res.json(derivativeExchangeData); } catch (error) { console.error(`Error fetching data for derivative exchange ${req.params.exchangeId}:`, error); res.status(500).json({ error: `Failed to fetch data for derivative exchange ${req.params.exchangeId}` }); } }); // Get derivative exchanges list app.get('/api/derivatives/exchanges/list', async (req, res) => { try { const derivativeExchangesList = await client.derivativesExchangesList(); res.json(derivativeExchangesList); } catch (error) { console.error('Error fetching derivative exchanges list:', error); res.status(500).json({ error: 'Failed to fetch derivative exchanges list' }); } }); // === NFTs Endpoints (beta) === // Get NFTs list app.get('/api/nfts/list', async (req, res) => { try { const { order, asset_platform_id, per_page, page } = req.query; const nftsList = await client.nftsList({ order, asset_platform_id, per_page: per_page ? parseInt(per_page) : 100, page: page ? parseInt(page) : 1 }); res.json(nftsList); } catch (error) { console.error('Error fetching NFTs list:', error); res.status(500).json({ error: 'Failed to fetch NFTs list' }); } }); // Get NFT by ID app.get('/api/nfts/:id', async (req, res) => { try { const { id } = req.params; const nftData = await client.nftsId({ id }); res.json(nftData); } catch (error) { console.error(`Error fetching NFT data for ${req.params.id}:`, error); res.status(500).json({ error: `Failed to fetch NFT data for ${req.params.id}` }); } }); // Get NFT by contract app.get('/api/nfts/:asset_platform_id/contract/:contract_address', async (req, res) => { try { const { asset_platform_id, contract_address } = req.params; const nftContractData = await client.nftsContract({ asset_platform_id, contract_address }); res.json(nftContractData); } catch (error) { console.error('Error fetching NFT contract data:', error); res.status(500).json({ error: 'Failed to fetch NFT contract data' }); } }); // === EXCHANGE RATES Endpoint === // Get exchange rates app.get('/api/exchange_rates', async (req, res) => { try { const exchangeRatesData = await client.exchangeRates(); res.json(exchangeRatesData); } catch (error) { console.error('Error fetching exchange rates:', error); res.status(500).json({ error: 'Failed to fetch exchange rates' }); } }); // === SEARCH Endpoint === // Search for coins, categories, and markets app.get('/api/search', async (req, res) => { try { const { query } = req.query; if (!query) { return res.status(400).json({ error: 'Missing required parameter: query' }); } const searchResults = await client.search({ query }); res.json(searchResults); } catch (error) { console.error('Error performing search:', error); res.status(500).json({ error: 'Failed to perform search' }); } }); // === TRENDING Endpoint === // Get trending coins app.get('/api/trending', async (req, res) => { try { const trendingCoins = await client.trending(); res.json(trendingCoins); } catch (error) { console.error('Error fetching trending coins:', error); res.status(500).json({ error: 'Failed to fetch trending coins' }); } }); // === GLOBAL Endpoints === // Get global cryptocurrency data app.get('/api/global', async (req, res) => { try { const apiKey = process.env.COINGECKO_API_KEY; const baseUrl = apiKey ? 'https://pro-api.coingecko.com/api/v3/global' : 'https://api.coingecko.com/api/v3/global'; if (!apiKey) { console.log('No API key found, using free CoinGecko API for global data'); } const headers = apiKey ? { 'x-cg-pro-api-key': apiKey } : {}; const response = await fetch(baseUrl, { headers }); if (!response.ok) { throw new Error(`Error from CoinGecko API: ${response.status} ${response.statusText}`); } const data = await response.json(); res.json(data); } catch (error) { console.error('Error fetching global data:', error); res.status(500).json({ error: 'Failed to fetch global data' }); } }); // Get global DeFi data app.get('/api/global/decentralized_finance_defi', async (req, res) => { try { const globalDefiData = await client.globalDefi(); res.json(globalDefiData); } catch (error) { console.error('Error fetching global DeFi data:', error); res.status(500).json({ error: 'Failed to fetch global DeFi data' }); } }); // === COMPANIES Endpoint (beta) === // Get public companies data app.get('/api/companies/public_treasury/:coin_id', async (req, res) => { try { const { coin_id } = req.params; if (coin_id !== 'bitcoin' && coin_id !== 'ethereum') { return res.status(400).json({ error: 'Invalid coin_id parameter. Only "bitcoin" or "ethereum" are supported.' }); } const companiesData = await client.companies({ coin_id }); res.json(companiesData); } catch (error) { console.error(`Error fetching companies data for ${req.params.coin_id}:`, error); res.status(500).json({ error: `Failed to fetch companies data for ${req.params.coin_id}` }); } }); // === SEARCH Endpoint === // Search for coins, categories, and markets app.get('/api/search/trending', async (req, res) => { try { const apiKey = process.env.COINGECKO_API_KEY; const baseUrl = apiKey ? 'https://pro-api.coingecko.com/api/v3/search/trending' : 'https://api.coingecko.com/api/v3/search/trending'; if (!apiKey) { console.log('No API key found, using free CoinGecko API for search/trending'); } const headers = apiKey ? { 'x-cg-pro-api-key': apiKey } : {}; const response = await fetch(baseUrl, { headers }); if (!response.ok) { throw new Error(`Error from CoinGecko API: ${response.status} ${response.statusText}`); } const data = await response.json(); res.json(data); } catch (error) { console.error('Error fetching trending data:', error); res.status(500).json({ error: 'Failed to fetch trending data' }); } }); // Start the server app.listen(port, () => { console.log(`CoinGecko API Server running on http://localhost:${port}`); });

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/GaplyDev01/coingecko-mcp-server'

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