get_crypto_prices
Retrieve live cryptocurrency prices including BTC, ETH, SOL and identify top 24-hour gainers and losers through micropayment calls.
Instructions
Get live cryptocurrency prices and top 24h movers. Returns BTC, ETH, SOL prices plus top gainers/losers. Costs 0.001 USDC per call (x402 micropayment on Base). Data sourced live from CoinGecko.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/index.ts:446-448 (handler)The handler for 'get_crypto_prices' tool - calls the /api/price-feed endpoint and returns the result
case 'get_crypto_prices': result = await callApi('/api/price-feed'); break; - src/index.ts:247-258 (schema)Tool definition for 'get_crypto_prices' with name, description, and empty inputSchema (no parameters required)
{ name: 'get_crypto_prices', description: 'Get live cryptocurrency prices and top 24h movers. Returns BTC, ETH, SOL prices plus top gainers/losers. ' + 'Costs 0.001 USDC per call (x402 micropayment on Base). ' + 'Data sourced live from CoinGecko.', inputSchema: { type: 'object', properties: {}, required: [], }, }, - src/index.ts:434-436 (registration)Registers the TOOLS array (containing get_crypto_prices) with the MCP server via ListToolsRequestSchema handler
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS, })); - src/index.ts:114-180 (helper)The callApi helper function that makes HTTP requests to the x402 API, handles 402 payment responses, timeouts, and error handling
async function callApi( endpoint: string, params: Record<string, string | number | undefined> = {} ): Promise<ApiResponse> { const url = new URL(`${API_BASE_URL}${endpoint}`); for (const [key, value] of Object.entries(params)) { if (value !== undefined && value !== '') { url.searchParams.set(key, String(value)); } } const fetchFn = await getX402Fetch(); let response: Response; const controller = new AbortController(); const fetchTimeout = setTimeout(() => controller.abort(), 30_000); try { response = await fetchFn(url.toString(), { headers: { 'Accept': 'application/json', 'User-Agent': `x402-api-mcp/${SERVER_VERSION}`, }, signal: controller.signal, }); } catch (err) { const isTimeout = err instanceof Error && err.name === 'AbortError'; throw new McpError( ErrorCode.InternalError, isTimeout ? `Request to ${endpoint} timed out after 30 seconds` : `Network error calling ${endpoint}: ${err instanceof Error ? err.message : String(err)}` ); } finally { clearTimeout(fetchTimeout); } if (response.status === 402) { // Clone before reading so we can fall back to text() if JSON parsing fails. // Without the clone, calling response.json() consumes the body; a subsequent // response.text() call then throws "body already used". const cloned = response.clone(); let paymentDetails: unknown; try { paymentDetails = await response.json(); } catch { paymentDetails = await cloned.text(); } return { status: 402, data: null, paymentRequired: true, paymentDetails }; } if (!response.ok) { const errorText = await response.text(); if (response.status === 400 || response.status === 422) { throw new McpError( ErrorCode.InvalidParams, `Invalid request to ${endpoint}: ${errorText}` ); } throw new McpError( ErrorCode.InternalError, `API error ${response.status} from ${endpoint}: ${errorText}` ); } const data = await response.json(); return { status: response.status, data }; }