Skip to main content
Glama
boldcommerce

Magento 2 MCP Server

by boldcommerce

get_revenue

Calculate total revenue for a Magento 2 store within specified date ranges and order status filters, with tax inclusion options.

Instructions

Get the total revenue for a given date range

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
date_rangeYesDate range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')
statusNoFilter by order status (e.g., 'processing', 'complete', 'pending')
include_taxNoWhether to include tax in the revenue calculation (default: true)

Implementation Reference

  • mcp-server.js:851-938 (registration)
    Registration of the 'get_revenue' MCP tool using server.tool(), including description, Zod input schema, and the complete inline async handler function that implements the revenue calculation logic.
    server.tool( "get_revenue", "Get the total revenue for a given date range", { date_range: z.string().describe("Date range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')"), status: z.string().optional().describe("Filter by order status (e.g., 'processing', 'complete', 'pending')"), include_tax: z.boolean().optional().describe("Whether to include tax in the revenue calculation (default: true)") }, async ({ date_range, status, include_tax = true }) => { try { // Parse the date range expression const dateRange = parseDateExpression(date_range); // Build the search criteria for the date range let searchCriteria = buildDateRangeFilter('created_at', dateRange.startDate, dateRange.endDate); // Add status filter if provided if (status) { searchCriteria += `&searchCriteria[filter_groups][2][filters][0][field]=status&` + `searchCriteria[filter_groups][2][filters][0][value]=${encodeURIComponent(status)}&` + `searchCriteria[filter_groups][2][filters][0][condition_type]=eq`; } // Fetch all orders using the helper function const allOrders = await fetchAllPages('/orders', searchCriteria); // Calculate total revenue let totalRevenue = 0; let totalTax = 0; let orderCount = 0; if (allOrders && Array.isArray(allOrders)) { orderCount = allOrders.length; allOrders.forEach(order => { // Use grand_total which includes tax, shipping, etc. totalRevenue += parseFloat(order.grand_total || 0); // Track tax separately totalTax += parseFloat(order.tax_amount || 0); }); } // Adjust revenue if tax should be excluded const revenueWithoutTax = totalRevenue - totalTax; const finalRevenue = include_tax ? totalRevenue : revenueWithoutTax; // Format the response const result = { query: { date_range: dateRange.description, status: status || 'All', include_tax: include_tax, period: { start_date: format(dateRange.startDate, 'yyyy-MM-dd'), end_date: format(dateRange.endDate, 'yyyy-MM-dd') } }, result: { revenue: parseFloat(finalRevenue.toFixed(2)), currency: 'USD', // This should be dynamically determined from the store configuration order_count: orderCount, average_order_value: orderCount > 0 ? parseFloat((finalRevenue / orderCount).toFixed(2)) : 0, tax_amount: parseFloat(totalTax.toFixed(2)) } }; return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error fetching revenue: ${error.message}` } ], isError: true }; } } );
  • The core handler function for the get_revenue tool. Parses date range, applies filters, fetches all orders via Magento API, computes total revenue (with optional tax exclusion), order count, average order value, and returns structured JSON response.
    async ({ date_range, status, include_tax = true }) => { try { // Parse the date range expression const dateRange = parseDateExpression(date_range); // Build the search criteria for the date range let searchCriteria = buildDateRangeFilter('created_at', dateRange.startDate, dateRange.endDate); // Add status filter if provided if (status) { searchCriteria += `&searchCriteria[filter_groups][2][filters][0][field]=status&` + `searchCriteria[filter_groups][2][filters][0][value]=${encodeURIComponent(status)}&` + `searchCriteria[filter_groups][2][filters][0][condition_type]=eq`; } // Fetch all orders using the helper function const allOrders = await fetchAllPages('/orders', searchCriteria); // Calculate total revenue let totalRevenue = 0; let totalTax = 0; let orderCount = 0; if (allOrders && Array.isArray(allOrders)) { orderCount = allOrders.length; allOrders.forEach(order => { // Use grand_total which includes tax, shipping, etc. totalRevenue += parseFloat(order.grand_total || 0); // Track tax separately totalTax += parseFloat(order.tax_amount || 0); }); } // Adjust revenue if tax should be excluded const revenueWithoutTax = totalRevenue - totalTax; const finalRevenue = include_tax ? totalRevenue : revenueWithoutTax; // Format the response const result = { query: { date_range: dateRange.description, status: status || 'All', include_tax: include_tax, period: { start_date: format(dateRange.startDate, 'yyyy-MM-dd'), end_date: format(dateRange.endDate, 'yyyy-MM-dd') } }, result: { revenue: parseFloat(finalRevenue.toFixed(2)), currency: 'USD', // This should be dynamically determined from the store configuration order_count: orderCount, average_order_value: orderCount > 0 ? parseFloat((finalRevenue / orderCount).toFixed(2)) : 0, tax_amount: parseFloat(totalTax.toFixed(2)) } }; return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error fetching revenue: ${error.message}` } ], isError: true }; } }
  • Zod schema defining input parameters for the get_revenue tool: required date_range string, optional status and include_tax.
    { date_range: z.string().describe("Date range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')"), status: z.string().optional().describe("Filter by order status (e.g., 'processing', 'complete', 'pending')"), include_tax: z.boolean().optional().describe("Whether to include tax in the revenue calculation (default: true)") },
  • Helper function to parse natural language date range expressions into startDate, endDate (Date objects) and a human-readable description, used by get_revenue and similar tools.
    function parseDateExpression(dateExpression) { const now = new Date(); const currentYear = now.getFullYear(); const currentMonth = now.getMonth(); const currentDay = now.getDate(); // Normalize the date expression const normalizedExpression = dateExpression.toLowerCase().trim(); // Handle relative date expressions switch (normalizedExpression) { case 'today': return { startDate: startOfDay(now), endDate: endOfDay(now), description: 'Today' }; case 'yesterday': const yesterday = subDays(now, 1); return { startDate: startOfDay(yesterday), endDate: endOfDay(yesterday), description: 'Yesterday' }; case 'this week': return { startDate: startOfWeek(now, { weekStartsOn: 1 }), // Week starts on Monday endDate: endOfDay(now), description: 'This week' }; case 'last week': const lastWeekStart = subDays(startOfWeek(now, { weekStartsOn: 1 }), 7); const lastWeekEnd = subDays(endOfWeek(now, { weekStartsOn: 1 }), 7); return { startDate: lastWeekStart, endDate: lastWeekEnd, description: 'Last week' }; case 'this month': return { startDate: startOfMonth(now), endDate: endOfDay(now), description: 'This month' }; case 'last month': const lastMonth = new Date(currentYear, currentMonth - 1, 1); return { startDate: startOfMonth(lastMonth), endDate: endOfMonth(lastMonth), description: 'Last month' }; case 'ytd': case 'this ytd': case 'this year to date': case 'year to date': return { startDate: startOfYear(now), endDate: endOfDay(now), description: 'Year to date' }; case 'last year': const lastYear = new Date(currentYear - 1, 0, 1); return { startDate: startOfYear(lastYear), endDate: endOfYear(lastYear), description: 'Last year' }; default: // Try to parse as ISO date or other common formats try { // Check if it's a single date (not a range) const parsedDate = parseISO(normalizedExpression); if (isValid(parsedDate)) { return { startDate: startOfDay(parsedDate), endDate: endOfDay(parsedDate), description: format(parsedDate, 'yyyy-MM-dd') }; } // Check if it's a date range in format "YYYY-MM-DD to YYYY-MM-DD" const rangeParts = normalizedExpression.split(' to '); if (rangeParts.length === 2) { const startDate = parseISO(rangeParts[0]); const endDate = parseISO(rangeParts[1]); if (isValid(startDate) && isValid(endDate)) { return { startDate: startOfDay(startDate), endDate: endOfDay(endDate), description: `${format(startDate, 'yyyy-MM-dd')} to ${format(endDate, 'yyyy-MM-dd')}` }; } } // If we can't parse it, throw an error throw new Error(`Unable to parse date expression: ${dateExpression}`); } catch (error) { throw new Error(`Invalid date expression: ${dateExpression}. ${error.message}`); } } }
  • Helper to fetch and concatenate all paginated results from a Magento API endpoint, handling dynamic pagination based on total_count.
    async function fetchAllPages(endpoint, baseSearchCriteria) { const pageSize = 100; // Or make this configurable if needed let currentPage = 1; let allItems = []; let totalCount = 0; do { // Build search criteria for the current page, ensuring baseSearchCriteria doesn't already have pagination let currentPageSearchCriteria = baseSearchCriteria; if (!currentPageSearchCriteria.includes('searchCriteria[pageSize]')) { currentPageSearchCriteria += `&searchCriteria[pageSize]=${pageSize}`; } if (!currentPageSearchCriteria.includes('searchCriteria[currentPage]')) { currentPageSearchCriteria += `&searchCriteria[currentPage]=${currentPage}`; } else { // If currentPage is already there, replace it (less common case) currentPageSearchCriteria = currentPageSearchCriteria.replace(/searchCriteria\[currentPage\]=\d+/, `searchCriteria[currentPage]=${currentPage}`); } // Make the API call for the current page const responseData = await callMagentoApi(`${endpoint}?${currentPageSearchCriteria}`); if (responseData.items && Array.isArray(responseData.items)) { allItems = allItems.concat(responseData.items); } // Update total count (only needs to be set once) if (currentPage === 1) { totalCount = responseData.total_count || 0; } // Check if we need to fetch more pages if (totalCount <= allItems.length || !responseData.items || responseData.items.length < pageSize) { break; // Exit loop if all items are fetched or last page had less than pageSize items } currentPage++; } while (true); // Loop continues until break return allItems; // Return the aggregated list of items }
  • Helper to construct Magento API searchCriteria query string for filtering records by date range on a given field.
    function buildDateRangeFilter(field, startDate, endDate) { const formattedStartDate = formatDateForMagento(startDate); const formattedEndDate = formatDateForMagento(endDate); return [ `searchCriteria[filter_groups][0][filters][0][field]=${field}`, `searchCriteria[filter_groups][0][filters][0][value]=${encodeURIComponent(formattedStartDate)}`, `searchCriteria[filter_groups][0][filters][0][condition_type]=gteq`, `searchCriteria[filter_groups][1][filters][0][field]=${field}`, `searchCriteria[filter_groups][1][filters][0][value]=${encodeURIComponent(formattedEndDate)}`, `searchCriteria[filter_groups][1][filters][0][condition_type]=lteq` ].join('&'); }

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/boldcommerce/magento2-mcp'

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