Skip to main content
Glama
CoinStatsHQ

CoinStats MCP Server

Official

get-portfolio-chart

Retrieve portfolio performance chart data from CoinStats by specifying a time range and optional share token to visualize cryptocurrency investment trends.

Instructions

Get portfolio performance chart data.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
shareTokenNoPortfolio share token. You can get your share token from the portfolio you want to retrive data from by clicking Share button on CoinStats web app portfolio tracker section - top right.
typeYesOne of 24h, 1w, 1m, 3m, 6m, 1y, all

Implementation Reference

  • Schema and configuration for the 'get-portfolio-chart' tool, including Zod parameter definitions, endpoint '/portfolio/chart', and description.
    { name: 'get-portfolio-chart', description: 'Get portfolio performance chart data.', endpoint: '/portfolio/chart', method: 'GET', parameters: { shareToken: z .string() .optional() .describe( 'Portfolio share token. You can get your share token from the portfolio you want to retrive data from by clicking Share button on CoinStats web app portfolio tracker section - top right.' ), type: z.string().describe('One of 24h, 1w, 1m, 3m, 6m, 1y, all'), }, },
  • Registration function that loops over tool configs (including get-portfolio-chart) and registers each with MCP server.tool, defining a generic handler that calls universalApiHandler for API tools.
    export function registerTools(server: McpServer, toolConfigs: ToolConfig<any>[]) { toolConfigs.forEach((config) => { server.tool(config.name, config.description, config.parameters, async (params: Record<string, any>) => { // Handle local operations if (config.isLocal) { // Handle specific local tools if (config.name === 'save-share-token') { await saveToCache('shareToken', params.shareToken); return { content: [ { type: 'text', text: 'Share token saved successfully', }, ], }; } if (config.name === 'get-share-token') { const shareToken = await getFromCache('shareToken'); return { content: [ { type: 'text', text: shareToken ? shareToken : 'No share token found in cache', isError: !shareToken, }, ], }; } // Future local tools can be added here // Default response for unhandled local tools return { content: [ { type: 'text', text: 'Operation completed', }, ], }; } // Handle API operations const basePath = config.basePath || COINSTATS_API_BASE; const method = config.method || 'GET'; // Methods that typically have a request body const bodyMethods = ['POST', 'PUT', 'PATCH', 'DELETE']; // For GET/DELETE requests, all params go in the URL // For POST/PUT/PATCH, send params as the body if (bodyMethods.includes(method.toUpperCase())) { return universalApiHandler(basePath, config.endpoint, method, {}, params); } else { return universalApiHandler(basePath, config.endpoint, method, params); } }); }); }
  • Primary handler function for API-based tools like get-portfolio-chart. Processes endpoint (e.g., '/portfolio/chart'), handles path/query params, invokes makeRequestCsApi, and returns MCP-formatted response.
    export async function universalApiHandler<T>( basePath: string, endpoint: string, method: string = 'GET', params: Record<string, any> = {}, body?: any ): Promise<{ content: Array<{ type: 'text'; text: string; isError?: boolean }>; }> { try { // Handle path parameters - replace {paramName} in endpoint with actual values let processedEndpoint = endpoint; let processedParams = { ...params }; // Find all path parameters in the endpoint (e.g., {coinId}, {id}, {type}) const pathParamMatches = endpoint.match(/\{([^}]+)\}/g); if (pathParamMatches) { for (const match of pathParamMatches) { const paramName = match.slice(1, -1); // Remove { and } if (processedParams[paramName] !== undefined) { // Replace the placeholder with the actual value processedEndpoint = processedEndpoint.replace(match, processedParams[paramName]); // Remove the parameter from query params since it's now part of the path delete processedParams[paramName]; } else { throw new Error(`Required path parameter '${paramName}' is missing`); } } } // MCP clients might not support '~' in parameter names, so we replace '-' with '~' specifically for the /coins endpoint before making the request. if (endpoint === '/coins') { processedParams = Object.entries(processedParams).reduce((acc, [key, value]) => { acc[key.replace(/-/g, '~')] = value; return acc; }, {} as Record<string, any>); } const url = `${basePath}${processedEndpoint}`; const data = await makeRequestCsApi<T>(url, method, processedParams, body); if (!data) { return { content: [{ type: 'text', text: 'Something went wrong', isError: true }], }; } return { content: [ { type: 'text', text: JSON.stringify(data), }, ], }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error}`, isError: true }], }; } }
  • src/index.ts:17-18 (registration)
    Main registration point where registerTools is invoked with allToolConfigs, including get-portfolio-chart, to set up the MCP server.
    // Register all tools from configurations registerTools(server, allToolConfigs);
  • Helper function that performs the HTTP fetch to CoinStats API endpoints, used by universalApiHandler for get-portfolio-chart.
    export async function makeRequestCsApi<T>(url: string, method: string = 'GET', params: Record<string, any> = {}, body?: any): Promise<T | null> { const headers = { 'X-API-KEY': COINSTATS_API_KEY, 'Content-Type': 'application/json', }; try { // Build request options const options: RequestInit = { method, headers }; // Add body for non-GET requests if provided if (method !== 'GET' && body) { options.body = JSON.stringify(body); } // Add query params for all requests const queryParams = new URLSearchParams(params); const queryString = queryParams.toString(); const urlWithParams = queryString ? `${url}?${queryString}` : url; const response = await fetch(urlWithParams, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return (await response.json()) as T; } catch (error) { return null; } }

Latest Blog Posts

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/CoinStatsHQ/coinstats-mcp'

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