Skip to main content
Glama

CoinStats MCP Server

Official

add-portfolio-transaction

Add cryptocurrency transactions to manual portfolios by specifying coin, type, date, amount, and price for accurate tracking and management.

Instructions

Add a transaction to a manual portfolio.

Input Schema

NameRequiredDescriptionDefault
amountYesTransaction amount
coinIdYesCoin ID
dateYesTransaction date in ISO format
feeNoTransaction fee
notesNoTransaction notes
priceYesPrice per coin
shareTokenNoPortfolio share token
typeYesTransaction type

Input Schema (JSON Schema)

{ "properties": { "amount": { "description": "Transaction amount", "type": "number" }, "coinId": { "description": "Coin ID", "type": "string" }, "date": { "description": "Transaction date in ISO format", "type": "string" }, "fee": { "description": "Transaction fee", "type": "number" }, "notes": { "description": "Transaction notes", "type": "string" }, "price": { "description": "Price per coin", "type": "number" }, "shareToken": { "description": "Portfolio share token", "type": "string" }, "type": { "description": "Transaction type", "type": "string" } }, "required": [ "coinId", "type", "date", "amount", "price" ], "type": "object" }

Implementation Reference

  • universalApiHandler: Core function that handles HTTP requests to the CoinStats API, processes path parameters, handles query params/body, fetches data, and formats response for MCP tool.
    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 }], }; } }
  • Tool handler function registered for each tool config. For 'add-portfolio-transaction' (POST), calls universalApiHandler with body=params.
    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); } });
  • Tool configuration defining name, description, endpoint, method=POST, and Zod schema for input parameters.
    { name: 'add-portfolio-transaction', description: 'Add a transaction to a manual portfolio.', endpoint: '/portfolio/transaction', method: 'POST', parameters: { shareToken: z.string().optional().describe('Portfolio share token'), // This endpoint requires a request body which would need to match the AddTransactionDto schema // For simplicity, we're defining a basic structure that matches the expected input coinId: z.string().describe('Coin ID'), type: z.string().describe('Transaction type'), date: z.string().describe('Transaction date in ISO format'), amount: z.number().describe('Transaction amount'), price: z.number().describe('Price per coin'), fee: z.number().optional().describe('Transaction fee'), notes: z.string().optional().describe('Transaction notes'), }, },
  • src/index.ts:17-18 (registration)
    Calls registerTools with allToolConfigs, registering 'add-portfolio-transaction' and all other tools to the MCP server.
    // Register all tools from configurations registerTools(server, allToolConfigs);

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