Skip to main content
Glama

evm_getnfttrades

Retrieve NFT trades for a specific contract address, with optional filtering by marketplace, date range, or block number to analyze transaction history.

Instructions

Get NFT trades for a given contract with the ability to filter by marketplace.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNoThe chain to queryeth
from_blockNoThe minimum block number from which to get the transfers * Provide the param 'from_block' or 'from_date' * If 'from_date' and 'from_block' are provided, 'from_block' will be used.
to_blockNoThe block number to get the trades from
from_dateNoThe start date from which to get the transfers (format in seconds or datestring accepted by momentjs) * Provide the param 'from_block' or 'from_date' * If 'from_date' and 'from_block' are provided, 'from_block' will be used.
to_dateNoThe end date from which to get the transfers (format in seconds or datestring accepted by momentjs) * Provide the param 'to_block' or 'to_date' * If 'to_date' and 'to_block' are provided, 'to_block' will be used.
marketplaceNoMarketplace from which to get the trades. See [supported Marketplaces](https://docs.moralis.io/web3-data-api/evm/nft-marketplaces).opensea
cursorNoThe cursor returned in the previous response (used for getting the next page).
limitNoThe desired page size of the result.
nft_metadataNoInclude the NFT Metadata of the NFT Token
addressYesThe address of the NFT contract

Implementation Reference

  • The core handler function that implements the execution logic for all dynamically generated API tools, including 'evm_getnfttrades'. It validates input using Zod (derived from OpenAPI schema), constructs the HTTP request (URL, params, headers, body, auth), executes via axios, and formats the response or error.
    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)
    Registers the CallToolRequestSchema handler, which looks up the tool definition by name (e.g., 'evm_getnfttrades') in the toolDefinitionMap and delegates execution to executeApiTool.
    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:26-44 (registration)
    Loads the OpenAPI spec, extracts tool definitions (including 'evm_getnfttrades' with prefix), filters blacklist, and builds the toolDefinitionMap used for registration and lookup.
    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; }
  • Parses OpenAPI document to extract tool definitions, generates MCP-compatible name by appending prefix ('evm_') to operationId/generated name, creates inputSchema from parameters and requestBody.
    export function extractToolsFromApi( api: OpenAPIV3DocumentX, prefix?: string ): McpToolDefinition[] { const tools: McpToolDefinition[] = []; const usedNames = new Set<string>(); const globalSecurity = api.security || []; if (!api.paths) return tools; for (const [path, pathItem] of Object.entries(api.paths)) { if (!pathItem) continue; for (const method of Object.values(OpenAPIV3.HttpMethods)) { const operation = pathItem[method]; if (!operation) continue; // Generate a unique name for the tool let baseName = operation.operationId || generateOperationId(method, path); if (!baseName) continue; // Sanitize the name to be MCP-compatible (only a-z, 0-9, _, -) baseName = baseName .replace(/\./g, '_') .replace(/[^a-z0-9_-]/gi, '_') .toLowerCase(); let finalToolName = baseName; let counter = 1; while (usedNames.has(finalToolName)) { finalToolName = `${baseName}_${counter++}`; } usedNames.add(finalToolName); // Get or create a description const description = operation.description || operation.summary || `Executes ${method.toUpperCase()} ${path}`; const prompt = operation['x-mcp-prompt']; // Generate input schema and extract parameters const { inputSchema, parameters, requestBodyContentType } = generateInputSchemaAndDetails(operation); // Extract parameter details for execution const executionParameters = parameters.map((p) => ({ name: p.name, in: p.in, })); // Determine security requirements const securityRequirements = operation.security === null ? globalSecurity : operation.security || globalSecurity; // Create the tool definition tools.push({ name: prefix + finalToolName, description, inputSchema, method, pathTemplate: path, parameters, executionParameters, requestBodyContentType, securityRequirements, operationId: baseName, prompt, }); } } return tools; }
  • Defines the EVM API configuration, including the 'evm_' prefix used for tool names like 'evm_getnfttrades', baseUrl, and OpenAPI spec URL from which the tool schema and paths are derived.
    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', },
Install Server

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