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
| Name | Required | Description | Default |
|---|---|---|---|
| date_range | Yes | 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 | No | Filter by order status (e.g., 'processing', 'complete', 'pending') | |
| include_tax | No | Whether 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 }; } } );
- mcp-server.js:859-937 (handler)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 }; } }
- mcp-server.js:854-858 (schema)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)") },
- mcp-server.js:23-124 (helper)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}`); } } }
- mcp-server.js:259-300 (helper)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 }
- mcp-server.js:137-149 (helper)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('&'); }