Skip to main content
Glama

evm_gettokenmetadata

Retrieve ERC20 token metadata including name, symbol, decimals, logo, total supply, categories, and spam status for contract addresses across multiple blockchain networks.

Instructions

Retrieve metadata (name, symbol, decimals, logo) for an ERC20 token contract, as well as off-chain metadata, total supply, categories, logos, spam status and more.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNoThe chain to queryeth
addressesYesThe addresses to get metadata for

Implementation Reference

  • The core handler function that implements the logic for executing the 'evm_gettokenmetadata' tool (and all other dynamic tools). It validates inputs with Zod schema derived from OpenAPI, builds the HTTP request using the tool's pathTemplate, method, parameters, applies API key auth from config or token, calls axios to Moralis EVM API, processes JSON response, and returns formatted text content.
    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:97-119 (registration)
    Registers the MCP 'tools/call' request handler. For 'evm_gettokenmetadata', it retrieves the tool definition from the map and invokes the generic executeApiTool handler.
    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:26-43 (registration)
    Dynamically generates and registers tool definitions by fetching/parsing OpenAPI spec from Moralis EVM API, extracting tools with 'evm_' prefix via extractToolsFromApi (which creates 'evm_gettokenmetadata' from matching operation), building the toolDefinitionMap used by handlers.
    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;
  • Generates the inputSchema (JSON Schema) for the tool definition of 'evm_gettokenmetadata' from the OpenAPI operation's parameters and requestBody. This schema is used for MCP tool description and runtime Zod validation.
    export function generateInputSchemaAndDetails( operation: OpenAPIV3.OperationObject, ): { inputSchema: JSONSchema7 | boolean; parameters: OpenAPIV3.ParameterObject[]; requestBodyContentType?: string; } { const properties: { [key: string]: JSONSchema7 | boolean } = {}; const required: string[] = []; // Process parameters const allParameters: OpenAPIV3.ParameterObject[] = Array.isArray( operation.parameters, ) ? operation.parameters.map((p) => p as OpenAPIV3.ParameterObject) : []; allParameters.forEach((param) => { if (!param.name || !param.schema) return; const paramSchema = mapOpenApiSchemaToJsonSchema( param.schema as OpenAPIV3.SchemaObject, ); if (typeof paramSchema === 'object') { paramSchema.description = param.description || paramSchema.description; } properties[param.name] = paramSchema; if (param.required) required.push(param.name); }); // Process request body (if present) let requestBodyContentType: string | undefined = undefined; if (operation.requestBody) { const opRequestBody = operation.requestBody as OpenAPIV3.RequestBodyObject; const jsonContent = opRequestBody.content?.['application/json']; const firstContent = opRequestBody.content ? Object.entries(opRequestBody.content)[0] : undefined; if (jsonContent?.schema) { requestBodyContentType = 'application/json'; const bodySchema = mapOpenApiSchemaToJsonSchema( jsonContent.schema as OpenAPIV3.SchemaObject, ); if (typeof bodySchema === 'object') { bodySchema.description = opRequestBody.description || bodySchema.description || 'The JSON request body.'; } properties['requestBody'] = bodySchema; if (opRequestBody.required) required.push('requestBody'); } else if (firstContent) { const [contentType] = firstContent; requestBodyContentType = contentType; properties['requestBody'] = { type: 'string', description: opRequestBody.description || `Request body (content type: ${contentType})`, }; if (opRequestBody.required) required.push('requestBody'); } } // Combine everything into a JSON Schema const inputSchema: JSONSchema7 = { type: 'object', properties, ...(required.length > 0 && { required }), }; return { inputSchema, parameters: allParameters, requestBodyContentType };
  • Configuration for EVM tools, providing 'evm_' prefix (so gettokenmetadata -> evm_gettokenmetadata), baseUrl for API calls, and specUrl from which the tool definitions including schemas and paths 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