Skip to main content
Glama

evm_gettimeseriesvolumebycategory

Fetch timeseries volume data including buy, sell, liquidity, and FDV for specific token categories across multiple blockchains. Filter by chain and timeframe to analyze market trends.

Instructions

Fetch timeseries buy volume, sell volume, liquidity and FDV for a specific category. Optionally filter by chain.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNoThe chain to queryeth
timeframeYesThe timeframe to query1d
categoryIdYesThe category id

Implementation Reference

  • The generic handler function `executeApiTool` that implements the core logic for all API-based tools, including `evm_gettimeseriesvolumebycategory`. It validates input, constructs HTTP request to Moralis API using tool definition (path, method, params, security), executes with axios, and formats response.
    export async function executeApiTool( toolName: string, definition: McpToolDefinition, toolArgs: JsonObject, allSecuritySchemes: Record<string, any>, token?: string, ): Promise<CallToolResult> { try { // Validate arguments against the input schema let validatedArgs: JsonObject; try { const zodSchema = getZodSchemaFromJsonSchema( definition.inputSchema, toolName, ); const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; validatedArgs = zodSchema.parse(argsToParse); } catch (error: unknown) { if (error instanceof ZodError) { const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; return { content: [{ type: 'text', text: validationErrorMessage }] }; } else { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: 'text', text: `Internal error during validation setup: ${errorMessage}`, }, ], }; } } // Prepare URL, query parameters, headers, and request body let urlPath = definition.pathTemplate; const queryParams: Record<string, any> = {}; const headers: Record<string, string> = { Accept: 'application/json', 'X-Moralis-Platform': 'MCP', }; let requestBodyData: any = undefined; // Apply parameters to the URL path, query, or headers definition.executionParameters.forEach((param) => { const value = validatedArgs[param.name]; if (typeof value !== 'undefined' && value !== null) { if (param.in === 'path') { urlPath = urlPath.replace( `{${param.name}}`, encodeURIComponent(String(value)), ); } else if (param.in === 'query') { queryParams[param.name] = value; } else if (param.in === 'header') { headers[param.name.toLowerCase()] = String(value); } } }); // Ensure all path parameters are resolved if (urlPath.includes('{')) { throw new Error(`Failed to resolve path parameters: ${urlPath}`); } // Construct the full URL const requestUrl = `${definition.baseUrl}${urlPath}`; // Handle request body if needed if ( definition.requestBodyContentType && typeof validatedArgs['requestBody'] !== 'undefined' ) { requestBodyData = validatedArgs['requestBody']; headers['content-type'] = definition.requestBodyContentType; } // Apply security requirements if available // Security requirements use OR between array items and AND within each object const appliedSecurity = definition.securityRequirements?.find((req) => { // Try each security requirement (combined with OR) return Object.entries(req).every(([schemeName, scopesArray]) => { const scheme = allSecuritySchemes[schemeName]; if (!scheme) return false; // API Key security (header, query, cookie) if (scheme.type === 'apiKey') { return !!token || !!Config.MORALIS_API_KEY; } return false; }); }); // If we found matching security scheme(s), apply them if (appliedSecurity) { // Apply each security scheme from this requirement (combined with AND) for (const [schemeName, scopesArray] of Object.entries(appliedSecurity)) { const scheme = allSecuritySchemes[schemeName]; // API Key security if (scheme?.type === 'apiKey') { const apiKey = token || Config.MORALIS_API_KEY; if (apiKey) { if (scheme.in === 'header') { headers[scheme.name.toLowerCase()] = apiKey; console.error( `Applied API key '${schemeName}' in header '${scheme.name}'`, ); } } } } } // Log warning if security is required but not available else if (definition.securityRequirements?.length > 0) { // First generate a more readable representation of the security requirements const securityRequirementsString = definition.securityRequirements .map((req) => { const parts = Object.entries(req) .map(([name, scopesArray]) => { const scopes = scopesArray as string[]; if (scopes.length === 0) return name; return `${name} (scopes: ${scopes.join(', ')})`; }) .join(' AND '); return `[${parts}]`; }) .join(' OR '); console.warn( `Tool '${toolName}' requires security: ${securityRequirementsString}, but no suitable credentials found.`, ); } // Prepare the axios request configuration const config: AxiosRequestConfig = { method: definition.method.toUpperCase(), url: requestUrl, params: queryParams, headers: headers, ...(requestBodyData !== undefined && { data: requestBodyData }), }; // Log request info to stderr (doesn't affect MCP output) console.error( `Executing tool "${toolName}": ${config.method} ${config.url}`, ); // Execute the request const response = await axios(config); // Process and format the response let responseText = ''; const contentType = response.headers['content-type']?.toLowerCase() || ''; // Handle JSON responses if ( contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null ) { try { responseText = JSON.stringify(response.data, null, 2); } catch (e) { responseText = '[Stringify Error]'; } } // Handle string responses else if (typeof response.data === 'string') { responseText = response.data; } // Handle other response types else if (response.data !== undefined && response.data !== null) { responseText = String(response.data); } // Handle empty responses else { responseText = `(Status: ${response.status} - No body content)`; } // Return formatted response return { content: [ { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}`, }, ], }; } catch (error: unknown) { // Handle errors during execution let errorMessage: string; // Format Axios errors specially if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } // Handle standard errors else if (error instanceof Error) { errorMessage = error.message; } // Handle unexpected error types else { errorMessage = `Unexpected error: ${String(error)}`; } // Log error to stderr console.error( `Error during execution of tool '${toolName}':`, errorMessage, ); // Return error message to client return { content: [{ type: 'text', text: errorMessage }] }; } }
  • src/server.ts:96-120 (registration)
    MCP server registration of the CallTool handler, which looks up the tool definition by name (e.g., 'evm_gettimeseriesvolumebycategory') and delegates to the generic executeApiTool handler.
    server.setRequestHandler( CallToolRequestSchema, async (request: CallToolRequest, c): Promise<CallToolResult> => { const { name: toolName, arguments: toolArgs } = request.params; const toolDefinition = toolDefinitionMap[toolName]; if (!toolDefinition) { console.error(`Error: Unknown tool requested: ${toolName}`); return { content: [ { type: 'text', text: `Error: Unknown tool requested: ${toolName}`, }, ], }; } return executeApiTool( toolName, toolDefinition, toolArgs ?? {}, securitySchemes, c.authInfo?.token, ); }, );
  • src/server.ts:85-94 (registration)
    MCP server registration of ListTools handler, which provides the dynamically generated schema and description for all tools including `evm_gettimeseriesvolumebycategory`.
    server.setRequestHandler(ListToolsRequestSchema, async () => { const toolsForClient: Tool[] = Object.values(toolDefinitionMap).map( (def) => ({ name: def.name, description: def.description, inputSchema: def.inputSchema, }), ); return { tools: toolsForClient }; });
  • Loads OpenAPI spec for EVM/Solana, extracts tool definitions with prefix (e.g., 'evm_'), applies blacklist, stores in toolDefinitionMap used for registration and execution. This is where `evm_gettimeseriesvolumebycategory` gets registered dynamically.
    async function mapToolDefinitions(config: SchemaConfig) { const spec = (await getSpec(config.specUrl)) as OpenAPIV3DocumentX; const api = (await SwaggerParser.dereference(spec)) as OpenAPIV3DocumentX; const tools = extractToolsFromApi(api, config.prefix); const blacklist = Array.isArray(api['x-mcp-blacklist']) ? api['x-mcp-blacklist'].map((e) => `${config.prefix}${e.toLowerCase()}`) : []; const toolDefinitionMap: Record<string, McpToolDefinition> = {}; for (const tool of tools) { if (blacklist.includes(tool.name)) continue; toolDefinitionMap[tool.name] = { ...tool, baseUrl: config.baseUrl, }; } return toolDefinitionMap; }
  • Configuration for EVM tools, defining the 'evm_' prefix matching the tool name, base API URL, and OpenAPI spec URL from which the tool schemas and definitions are extracted.
    const configs: Record<string, SchemaConfig> = { evm: { prefix: 'evm_', baseUrl: process.env.API_BASE_URL || 'https://deep-index.moralis.io/api/v2.2', specUrl: process.env.API_SPEC_URL || 'https://deep-index.moralis.io/api-docs-2.2/v2.2/swagger.json', },

Other Tools

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/MoralisWeb3/moralis-mcp-server'

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