Skip to main content
Glama
CoinStatsHQ

CoinStats MCP Server

Official

get-exchange-balance

Retrieve cryptocurrency balance data from connected exchanges to monitor portfolio holdings and track asset distribution.

Instructions

Get the balance data for a provided Exchange.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
connectionFieldsYesThe credentials given from exchange. key, secret etc.
connectionIdYesThe exchange connection id

Implementation Reference

  • The inline handler function registered for the 'get-exchange-balance' tool (and all API tools). It determines if local or API, then for API calls universalApiHandler with basePath, endpoint '/exchange/balance', 'POST', empty query params, and tool params as body.
    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);
        }
    });
  • ToolConfig defining the name, description, input schema (Zod validators for parameters), endpoint, and method for the 'get-exchange-balance' tool.
    {
        name: 'get-exchange-balance',
        description: 'Get the balance data for a provided Exchange.',
        endpoint: '/exchange/balance',
        method: 'POST',
        parameters: {
            connectionFields: z.object({}).describe('The credentials given from exchange. key, secret etc.'),
            connectionId: z.string().describe('The exchange connection id'),
        },
    },
  • src/index.ts:17-18 (registration)
    Invocation of registerTools with allToolConfigs, which registers the 'get-exchange-balance' tool on the MCP server.
    // Register all tools from configurations
    registerTools(server, allToolConfigs);
  • The registerTools function iterates over tool configs (including get-exchange-balance) and calls server.tool to register each tool with its handler.
    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);
                }
            });
        });
    }
  • Universal API handler invoked by the tool handler to process path parameters, construct URL, make the HTTP request to CoinStats API, and format the response for MCP.
    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 }],
            };
        }
    }

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